diff --git a/.editorconfig b/.editorconfig index e49ab5718..66990769e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,23 +1,17 @@ -; top-most EditorConfig file +# editorconfig.org + root = true -; Unix-style newlines [*] -end_of_line = lf charset = utf-8 - -[*.php] -indent_style = space +end_of_line = lf indent_size = 4 - -[*.twig] indent_style = space -indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true -[*.yaml] -indent_style = space -indent_size = 4 +[{compose.yaml,compose.*.yaml}] +indent_size = 2 -[*.yml] -indent_style = space -indent_size = 4 +[*.md] +trim_trailing_whitespace = false diff --git a/.env.dist b/.env.dist index 881374f80..d8e0de9b3 100644 --- a/.env.dist +++ b/.env.dist @@ -1,7 +1,18 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: # -# You should NOT use this file in production, but instead move the environment variables to your webserver configuration. -# The .env file is only existing to simplify the initial setup! +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides # +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# https://symfony.com/doc/current/configuration/secrets.html +# +# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration #================================================================================ # Configure your database connection and set the correct server version. @@ -16,32 +27,34 @@ # For MySQL that would be "serverVersion=5.7" as in: # DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=5.7 # -# For MariaDB it would be "serverVersion=10.5.8-MariaDB": -# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB +# For MariaDB it would be "serverVersion=10.11.15-MariaDB": +# DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.11.15-MariaDB # -DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB +DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.11.15-MariaDB -#================================================================================ -# The full documentation can be found at https://www.kimai.org/documentation/emails.html -# -# Email will be sent with this address as sender: -MAILER_FROM=kimai@example.com -# Email connection (disabled by default) - see documentation for the format -MAILER_URL=null://null - -#================================================================================ -# do not change, unless you are developing for Kimai -APP_ENV=prod - -#================================================================================ -# should be changed to a unique character sequence, used for hashing cookies -APP_SECRET=change_this_to_something_unique - -#================================================================================ # Running behind reverse proxies? Try these: # TRUSTED_PROXIES=127.0.0.1,127.0.0.2 # TRUSTED_HOSTS=localhost|example.com -#================================================================================ -# unlikely, that you need to change this one -CORS_ALLOW_ORIGIN=^https?://localhost(:[0-9]+)?$ +###> symfony/framework-bundle ### +APP_ENV=prod +APP_SECRET= +APP_SHARE_DIR=var/share +###< symfony/framework-bundle ### + +###> symfony/mailer ### +# Documentation at https://www.kimai.org/documentation/emails.html +MAILER_FROM=kimai@example.com +# Email connection (disabled by default) - see documentation for the format +MAILER_URL=null://null +###< symfony/mailer ### + +###> nelmio/cors-bundle ### +CORS_ALLOW_ORIGIN='^https?://(localhost|127\.0\.0\.1)(:[0-9]+)?$' +###< nelmio/cors-bundle ### + +###> symfony/routing ### +# Configure how to generate URLs in non-HTTP contexts, such as CLI commands. +# See https://symfony.com/doc/current/routing.html#generating-urls-in-commands +DEFAULT_URI=http://localhost +###< symfony/routing ### diff --git a/.gitattributes b/.gitattributes index 560405bbd..e7061a653 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,8 +5,10 @@ tests export-ignore .codecov.yml export-ignore .editorconfig export-ignore eslint.config.js export-ignore +eslint.config.mjs export-ignore .gitattributes export-ignore .gitignore export-ignore +.php-cs-fixer.dist.php export-ignore php-cs-fixer.dist.php export-ignore babel.config.js export-ignore package.json export-ignore @@ -15,4 +17,4 @@ phpstan.neon export-ignore phpstan.sh export-ignore phpunit.xml.dist export-ignore webpack.config.js export-ignore -yarn.lock export-ignore \ No newline at end of file +yarn.lock export-ignore diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 8b369ed68..7ee3630ba 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -19,7 +19,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 strategy: matrix: - php: ['8.1', '8.2', '8.3', '8.4', '8.5'] + php: ['8.4', '8.5'] name: Integration (${{ matrix.php }}) steps: diff --git a/.gitignore b/.gitignore index 40a21331e..5d8c1e0e2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,9 @@ # some hosters require a htaccess to change the PHP version /public/.htaccess -/.env-* /.idea/ .DS_Store +var/templates/ + # custom apache rules e.g. to deactivate ioncube loader /public/.user.ini @@ -14,6 +15,7 @@ # YARN 2 /.yarnrc.yml /.yarn +/.pnp.* # for keeping empty directories /config/packages/local.yaml @@ -21,6 +23,7 @@ /var/dev/* /var/data/* /var/cache/* +/var/share/* /var/invoices* /var/export* /var/log/* @@ -34,7 +37,6 @@ /.env.local.php /.env.*.local /config/secrets/prod/prod.decrypt.private.php -.env /public/bundles/ /vendor/ ###< symfony/framework-bundle ### @@ -45,9 +47,8 @@ ###< phpunit/phpunit ### ###> friendsofphp/php-cs-fixer ### -.php_cs -.php_cs.cache -.php-cs-fixer.cache +/.php-cs-fixer.php +/.php-cs-fixer.cache ###< friendsofphp/php-cs-fixer ### ###> symfony/phpunit-bridge ### diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 22e4aa646..8302e1143 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Send your ideas, code reviews, pull requests and feature requests to help to imp - Make your changes in a new git branch, based on the latest code in `main` - Apply our code-style by running `composer codestyle-fix` - Run the static code analysis with `composer phpstan` -- Verify everything still works with `composer tests-unit` +- Verify everything still works with `composer tests` - Add tests for your changes Further documentation can be found in the [developer documentation](https://www.kimai.org/documentation/developers.html). diff --git a/UPGRADING-2.md b/UPGRADING-2.md new file mode 100644 index 000000000..67733df6e --- /dev/null +++ b/UPGRADING-2.md @@ -0,0 +1,50 @@ +# Upgrading Kimai - Version 2.x + +_Make sure to create a backup before you start!_ + +Read the [updates documentation](https://www.kimai.org/documentation/updates.html) to find out how +you can upgrade your Kimai installation to the latest stable release. + +Check below if there are more version specific steps required, which need to be executed after the normal update process. +Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation. + +## [2.0.30](https://github.com/kimai/kimai/releases/tag/2.0.30) + +The `DATABASE_URL` in your environment settings (e.g. [.env](https://github.com/kimai/kimai/issues/4246), [docker-compose.yaml](https://github.com/tobybatch/kimai2/issues/531) or webserver config) +now requires the `charset` and `serverVersion` params, e.g.: `DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB` (examples in `.env`). + +## [2.0](https://github.com/kimai/kimai/releases/tag/2.0) + +**!! This release requires minimum PHP version to 8.1 !!** + +### Breaking changes + +- All plugins need to be updated: delete all previous version from your installation (`rm -r var/plugins/*`) before updating! +- The `local.yaml` is not compatible with old version, remove it before the update and then re-create it after everything works + - removed: configuring the `dashboard` is not supported any longer + - removed: custom translation files via `theme.branding.translation` + - removed: changing the plugin directory via `kimai.plugin_dir` + +### Developer + +Developer read the full documentation at [https://www.kimai.org/documentation/migration-v2.html](https://www.kimai.org/documentation/migration-v2.html). + +- Invoice renderer and templates for XML, JSON and TEXT were moved to the [Extended invoicing plugin](https://www.kimai.org/store/invoice-bundle.html) (install if you use one of those) +- Moved `company.docx` to [external repo](https://github.com/kimai/invoice-templates/tree/main/docx-company) (needs to be re-uploaded if you want to keep on using it!) +- Role names are forced to be uppercase +- Removed unused `public/avatars/` directory +- Time-tracking mode `duration_only` was removed, existing installations will be switched to `duration_fixed_begin` +- Removed Twig filters. You might have to replace them in your custom export/invoice templates: + - `date_full` => `date_time` + - `duration_decimal` => `duration(true)` + - `currency` => `currency_name` + - `country` => `country_name` + - `language` => `language_name` +- Removed support for custom translation files (use [TranslationBundle](https://www.kimai.org/store/translation-bundle.html) instead or write your own plugin) +- Removed all 3rd party mailer packages, you need to install them manually (ONLY if you used a short syntax to configure the `MAILER_URL` in `.env`): + - `composer require symfony/amazon-mailer` + - `composer require symfony/google-mailer` + - `composer require symfony/mailchimp-mailer` + - `composer require symfony/mailgun-mailer` + - `composer require symfony/postmark-mailer` + - `composer require symfony/sendgrid-mailer` diff --git a/UPGRADING-3.md b/UPGRADING-3.md index eccea7112..29a1e970f 100644 --- a/UPGRADING-3.md +++ b/UPGRADING-3.md @@ -11,16 +11,22 @@ Perform EACH version specific task between your version and the new one, otherwi **!! This release requires minimum PHP version 8.4 !!** +### Rename .env + +Rename your file `.env` to `.env.local` or even better: move all variables to your webserver/container environment. + ### Developer -Do not use method chaining: all fluent interface, especially in Entities, are no longer supported. +Do not use method chaining: all fluent interface, especially in Entities, are no longer supported. -Removed translations: -- `action.edit`: use `edit` instead -- `my.profile`: use `user_profile` instead -- `stats.userAmountToday`: use `` instead -- `stats.userAmountWeek`: use `` instead -- `stats.userAmountMonth`: use `` instead -- `stats.userAmountYear`: use `` instead -- `stats.userAmountTotal`: use `` instead -- `update_multiple` \ No newline at end of file +- Require PHP 8.4 +- Bump to Symfony 7.4 +- Removed old API token `X-AUTH-USER` and `X-AUTH-TOKEN` +- Removed `TimesheetConstraint` - use a normal `Constraint` as base class and attach the `#[App\Validator\Attribute\TimesheetConstraint]` attribute +- Removed `ProjectConstraint` - use a `FormExtension` and attach your custom constraints +- Interface `MetaTableTypeInterface` has new methods: `getSection()`, `setSection()` +- Interface `ExportRendererInterface` has new methods: `getType()`, `isInternal()` +- Interface `ExportableItem` has new methods: `getTags()`, `getBreak()` +- Removed and renamed translations, most important `action.edit` => `edit`, `my.profile` => `user_profile` +- Removed `User::isExportDecimal()` + - Use duration format `HH:mm` in default PDF exports diff --git a/UPGRADING.md b/UPGRADING.md index 67733df6e..de81164f4 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,50 +1,3 @@ -# Upgrading Kimai - Version 2.x +# Upgrading Kimai -_Make sure to create a backup before you start!_ - -Read the [updates documentation](https://www.kimai.org/documentation/updates.html) to find out how -you can upgrade your Kimai installation to the latest stable release. - -Check below if there are more version specific steps required, which need to be executed after the normal update process. -Perform EACH version specific task between your version and the new one, otherwise you risk data inconsistency or a broken installation. - -## [2.0.30](https://github.com/kimai/kimai/releases/tag/2.0.30) - -The `DATABASE_URL` in your environment settings (e.g. [.env](https://github.com/kimai/kimai/issues/4246), [docker-compose.yaml](https://github.com/tobybatch/kimai2/issues/531) or webserver config) -now requires the `charset` and `serverVersion` params, e.g.: `DATABASE_URL=mysql://user:password@127.0.0.1:3306/database?charset=utf8mb4&serverVersion=10.5.8-MariaDB` (examples in `.env`). - -## [2.0](https://github.com/kimai/kimai/releases/tag/2.0) - -**!! This release requires minimum PHP version to 8.1 !!** - -### Breaking changes - -- All plugins need to be updated: delete all previous version from your installation (`rm -r var/plugins/*`) before updating! -- The `local.yaml` is not compatible with old version, remove it before the update and then re-create it after everything works - - removed: configuring the `dashboard` is not supported any longer - - removed: custom translation files via `theme.branding.translation` - - removed: changing the plugin directory via `kimai.plugin_dir` - -### Developer - -Developer read the full documentation at [https://www.kimai.org/documentation/migration-v2.html](https://www.kimai.org/documentation/migration-v2.html). - -- Invoice renderer and templates for XML, JSON and TEXT were moved to the [Extended invoicing plugin](https://www.kimai.org/store/invoice-bundle.html) (install if you use one of those) -- Moved `company.docx` to [external repo](https://github.com/kimai/invoice-templates/tree/main/docx-company) (needs to be re-uploaded if you want to keep on using it!) -- Role names are forced to be uppercase -- Removed unused `public/avatars/` directory -- Time-tracking mode `duration_only` was removed, existing installations will be switched to `duration_fixed_begin` -- Removed Twig filters. You might have to replace them in your custom export/invoice templates: - - `date_full` => `date_time` - - `duration_decimal` => `duration(true)` - - `currency` => `currency_name` - - `country` => `country_name` - - `language` => `language_name` -- Removed support for custom translation files (use [TranslationBundle](https://www.kimai.org/store/translation-bundle.html) instead or write your own plugin) -- Removed all 3rd party mailer packages, you need to install them manually (ONLY if you used a short syntax to configure the `MAILER_URL` in `.env`): - - `composer require symfony/amazon-mailer` - - `composer require symfony/google-mailer` - - `composer require symfony/mailchimp-mailer` - - `composer require symfony/mailgun-mailer` - - `composer require symfony/postmark-mailer` - - `composer require symfony/sendgrid-mailer` +The most recent version is Kimai 3, please read the changelog at [UPGRADING-3.md](UPGRADING-3.md). diff --git a/assets/js/KimaiLoader.js b/assets/js/KimaiLoader.js index 8896f78e1..0450027fd 100644 --- a/assets/js/KimaiLoader.js +++ b/assets/js/KimaiLoader.js @@ -43,6 +43,7 @@ import KimaiHotkeys from "./plugins/KimaiHotkeys"; import KimaiRemoteModal from "./plugins/KimaiRemoteModal"; import KimaiUser from "./plugins/KimaiUser"; import KimaiAutocompleteTags from "./forms/KimaiAutocompleteTags"; +import KimaiMonthPicker from "./forms/KimaiMonthPicker"; import KimaiSortable from "./plugins/KimaiSortable"; export default class KimaiLoader { @@ -77,6 +78,7 @@ export default class KimaiLoader { kimai.registerPlugin(new KimaiTeamForm()); kimai.registerPlugin(new KimaiCopyDataForm()); kimai.registerPlugin(new KimaiDateNowForm()); + kimai.registerPlugin(new KimaiMonthPicker()); kimai.registerPlugin(new KimaiForm()); kimai.registerPlugin(new KimaiHotkeys()); diff --git a/assets/js/forms/KimaiAutocompleteTags.js b/assets/js/forms/KimaiAutocompleteTags.js index d55a134e8..353a8c559 100644 --- a/assets/js/forms/KimaiAutocompleteTags.js +++ b/assets/js/forms/KimaiAutocompleteTags.js @@ -24,7 +24,7 @@ export default class KimaiAutocompleteTags extends KimaiAutocomplete { API.get(apiUrl, {'name': query}, (data) => { let results = []; for (let item of data) { - results.push({text: item.name, value: item.name, color: item.color}); + results.push({text: item.name, value: item.name, color: item['color-safe']}); } callback(results); }, () => { diff --git a/assets/js/forms/KimaiMonthPicker.js b/assets/js/forms/KimaiMonthPicker.js new file mode 100644 index 000000000..c0ba4e7fc --- /dev/null +++ b/assets/js/forms/KimaiMonthPicker.js @@ -0,0 +1,44 @@ +/* + * This file is part of the Kimai time-tracking app. + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/*! + * [KIMAI] KimaiDatePicker: single date selects (currently unused) + */ + +import KimaiFormPlugin from "./KimaiFormPlugin"; + +export default class KimaiMonthPicker extends KimaiFormPlugin { + + /** + * @param {HTMLFormElement} form + * @return boolean + */ + supportsForm(form) // eslint-disable-line no-unused-vars + { + return true; + } + + /** + * @param {HTMLFormElement} form + */ + activateForm(form) + { + const input = document.createElement('input'); + input.setAttribute('type','month'); + + const notADateValue = 'not-a-month'; + input.setAttribute('value', notADateValue); + + if (input.value === notADateValue) { + const polyfills = form.querySelectorAll('a.input-month-polyfill'); + polyfills.forEach(i => i.classList.toggle('d-none')); + const inputs = form.querySelectorAll('input[type="month"]'); + inputs.forEach(i => i.classList.toggle('d-none')); + } + } + +} diff --git a/bin/console b/bin/console index 33b63f450..9111f93b3 100755 --- a/bin/console +++ b/bin/console @@ -6,8 +6,8 @@ use App\ConsoleApplication; set_time_limit(0); -if (!is_file(dirname(__DIR__).'/vendor/autoload_runtime.php')) { - throw new LogicException('Symfony Runtime is missing. Try running "composer require symfony/runtime".'); +if (!is_dir(dirname(__DIR__).'/vendor')) { + throw new LogicException('Dependencies are missing. Try running "composer install".'); } require_once dirname(__DIR__).'/vendor/autoload_runtime.php'; diff --git a/composer.json b/composer.json index 1aca19c6a..115283887 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,7 @@ } ], "require": { - "php": "8.1.*||8.2.*||8.3.*||8.4.*||8.5.*", + "php": "8.4.*||8.5.*", "ext-gd": "*", "ext-intl": "*", "ext-json": "*", @@ -29,11 +29,11 @@ "composer/semver": "^3.3", "doctrine/doctrine-bundle": "^2.7", "doctrine/doctrine-migrations-bundle": "^3.3", - "doctrine/orm": "^2.8", + "doctrine/orm": "^3.0", "easybill/zugferd-php": "^2.1", - "endroid/qr-code": "^4.8", - "erusev/parsedown": "^1.6", - "friendsofsymfony/rest-bundle": "^3.0", + "endroid/qr-code": "^6.0", + "parsedown/parsedown": "^1.6", + "friendsofsymfony/rest-bundle": "3.9.0-beta1", "gedmo/doctrine-extensions": "^3.6", "horstoeko/zugferd": "^1.0", "horstoeko/zugferdublbridge": "^1.0", @@ -45,37 +45,38 @@ "nelmio/cors-bundle": "^2.0", "onelogin/php-saml": "^4.0", "openspout/openspout": "^4.0", - "pagerfanta/pagerfanta": "^3.0", + "pagerfanta/pagerfanta": "^4.0", "phpoffice/phpspreadsheet": "^2.0", "phpoffice/phpword": "^1.0", "psr/container": "^2.0", "psr/log": "^3.0", - "scheb/2fa-backup-code": "^6.2", - "scheb/2fa-bundle": "^6.2", - "scheb/2fa-totp": "^6.2", - "symfony/asset": "^6.0", - "symfony/console": "^6.0", - "symfony/dotenv": "^6.0", - "symfony/expression-language": "^6.0", + "scheb/2fa-backup-code": "^7.11", + "scheb/2fa-bundle": "^7.11", + "scheb/2fa-totp": "^7.11", + "symfony/asset": "^7.0", + "symfony/console": "^7.0", + "symfony/dependency-injection": "^7.0", + "symfony/dotenv": "^7.0", + "symfony/expression-language": "^7.0", "symfony/flex": "^2", - "symfony/form": "^6.0", - "symfony/framework-bundle": "^6.0", - "symfony/http-client": "^6.0", - "symfony/intl": "^6.0", - "symfony/mailer": "^6.0", - "symfony/mime": "^6.0", + "symfony/form": "^7.0", + "symfony/framework-bundle": "^7.0", + "symfony/http-client": "^7.0", + "symfony/intl": "^7.0", + "symfony/mailer": "^7.0", + "symfony/mime": "^7.0", "symfony/monolog-bundle": "^3.4", - "symfony/process": "^6.0", - "symfony/rate-limiter": "^6.0", - "symfony/runtime": "^6.0", - "symfony/security-bundle": "^6.0", - "symfony/security-csrf": "^6.0", - "symfony/serializer": "^6.0", - "symfony/translation": "^6.0", - "symfony/twig-bundle": "^6.0", - "symfony/validator": "^6.0", + "symfony/process": "^7.0", + "symfony/rate-limiter": "^7.0", + "symfony/runtime": "^7.0", + "symfony/security-bundle": "^7.0", + "symfony/security-csrf": "^7.0", + "symfony/serializer": "^7.0", + "symfony/translation": "^7.0", + "symfony/twig-bundle": "^7.0", + "symfony/validator": "^7.0", "symfony/webpack-encore-bundle": "^2.0", - "symfony/yaml": "^6.0", + "symfony/yaml": "^7.0", "twig/cssinliner-extra": "^3.0", "twig/extra-bundle": "^3.0", "twig/inky-extra": "^3.0", @@ -95,14 +96,14 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^10.0", - "symfony/browser-kit": "^6.0", - "symfony/css-selector": "^6.0", - "symfony/debug-bundle": "^6.0", - "symfony/dom-crawler": "^6.0", - "symfony/phpunit-bridge": "^6.0", - "symfony/stopwatch": "^6.0", - "symfony/var-dumper": "^6.0", - "symfony/web-profiler-bundle": "^6.0" + "symfony/browser-kit": "^7.0", + "symfony/css-selector": "^7.0", + "symfony/debug-bundle": "^7.0", + "symfony/dom-crawler": "^7.0", + "symfony/phpunit-bridge": "^7.0", + "symfony/stopwatch": "^7.0", + "symfony/var-dumper": "^7.0", + "symfony/web-profiler-bundle": "^7.0" }, "repositories": [ { @@ -117,7 +118,7 @@ }, "optimize-autoloader": true, "platform": { - "php": "8.1.3" + "php": "8.4.4" }, "preferred-install": { "*": "dist" @@ -144,6 +145,9 @@ "symfony/polyfill-intl-idn": "*", "symfony/polyfill-intl-normalizer": "*", "symfony/polyfill-iconv": "*", + "symfony/polyfill-php84": "*", + "symfony/polyfill-php83": "*", + "symfony/polyfill-php82": "*", "symfony/polyfill-php81": "*", "symfony/polyfill-php80": "*", "symfony/polyfill-php74": "*", @@ -209,7 +213,7 @@ "symfony": { "id": "01C3FWRDJJEX9K6Y3A4XDFXPBR", "allow-contrib": true, - "require": "6.4.*" + "require": "7.4.*" } } } diff --git a/composer.lock b/composer.lock index aa1268831..8f8f3178e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "4f02c81fc72ab3bd887f6e8cf1361757", + "content-hash": "fce96dfab09cb39be7c01bc3617030c6", "packages": [ { "name": "azuyalabs/yasumi", - "version": "2.8.0", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/azuyalabs/yasumi.git", - "reference": "cc07874da062070fdc201a4297a7724f7d6aafb2" + "reference": "36005a0796b64bc07257f39c11c42f147fe5320f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/azuyalabs/yasumi/zipball/cc07874da062070fdc201a4297a7724f7d6aafb2", - "reference": "cc07874da062070fdc201a4297a7724f7d6aafb2", + "url": "https://api.github.com/repos/azuyalabs/yasumi/zipball/36005a0796b64bc07257f39c11c42f147fe5320f", + "reference": "36005a0796b64bc07257f39c11c42f147fe5320f", "shasum": "" }, "require": { @@ -30,8 +30,7 @@ "mikey179/vfsstream": "^1.6", "phpstan/phpstan": "^2.1", "phpstan/phpstan-deprecation-rules": "^2.0", - "phpunit/phpunit": "^8.5 || ^9.6", - "vimeo/psalm": "^6.12" + "phpunit/phpunit": "^8.5 || ^9.6" }, "suggest": { "ext-calendar": "For calculating the date of Easter" @@ -78,32 +77,33 @@ "type": "other" } ], - "time": "2025-07-13T15:40:05+00:00" + "time": "2025-12-29T16:13:54+00:00" }, { "name": "bacon/bacon-qr-code", - "version": "2.0.8", + "version": "v3.0.3", "source": { "type": "git", "url": "https://github.com/Bacon/BaconQrCode.git", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22" + "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/8674e51bb65af933a5ffaf1c308a660387c35c22", - "reference": "8674e51bb65af933a5ffaf1c308a660387c35c22", + "url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/36a1cb2b81493fa5b82e50bf8068bf84d1542563", + "reference": "36a1cb2b81493fa5b82e50bf8068bf84d1542563", "shasum": "" }, "require": { "dasprid/enum": "^1.0.3", "ext-iconv": "*", - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "phly/keep-a-changelog": "^2.1", - "phpunit/phpunit": "^7 | ^8 | ^9", - "spatie/phpunit-snapshot-assertions": "^4.2.9", - "squizlabs/php_codesniffer": "^3.4" + "phly/keep-a-changelog": "^2.12", + "phpunit/phpunit": "^10.5.11 || ^11.0.4", + "spatie/phpunit-snapshot-assertions": "^5.1.5", + "spatie/pixelmatch-php": "^1.2.0", + "squizlabs/php_codesniffer": "^3.9" }, "suggest": { "ext-imagick": "to generate QR code images" @@ -130,9 +130,9 @@ "homepage": "https://github.com/Bacon/BaconQrCode", "support": { "issues": "https://github.com/Bacon/BaconQrCode/issues", - "source": "https://github.com/Bacon/BaconQrCode/tree/2.0.8" + "source": "https://github.com/Bacon/BaconQrCode/tree/v3.0.3" }, - "time": "2022-12-07T17:46:57+00:00" + "time": "2025-11-19T17:15:36+00:00" }, { "name": "composer/pcre", @@ -340,100 +340,6 @@ }, "time": "2025-09-16T12:23:56+00:00" }, - { - "name": "doctrine/cache", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/cache.git", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb", - "reference": "1ca8f21980e770095a31456042471a57bc4c68fb", - "shasum": "" - }, - "require": { - "php": "~7.1 || ^8.0" - }, - "conflict": { - "doctrine/common": ">2.2,<2.4" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/coding-standard": "^9", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "psr/cache": "^1.0 || ^2.0 || ^3.0", - "symfony/cache": "^4.4 || ^5.4 || ^6", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - } - ], - "description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.", - "homepage": "https://www.doctrine-project.org/projects/cache.html", - "keywords": [ - "abstraction", - "apcu", - "cache", - "caching", - "couchdb", - "memcached", - "php", - "redis", - "xcache" - ], - "support": { - "issues": "https://github.com/doctrine/cache/issues", - "source": "https://github.com/doctrine/cache/tree/2.2.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache", - "type": "tidelift" - } - ], - "abandoned": true, - "time": "2022-05-20T20:07:39+00:00" - }, { "name": "doctrine/collections", "version": "2.4.0", @@ -520,141 +426,42 @@ ], "time": "2025-10-25T09:18:13+00:00" }, - { - "name": "doctrine/common", - "version": "3.5.0", - "source": { - "type": "git", - "url": "https://github.com/doctrine/common.git", - "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/d9ea4a54ca2586db781f0265d36bea731ac66ec5", - "reference": "d9ea4a54ca2586db781f0265d36bea731ac66ec5", - "shasum": "" - }, - "require": { - "doctrine/persistence": "^2.0 || ^3.0 || ^4.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "doctrine/coding-standard": "^9.0 || ^10.0", - "doctrine/collections": "^1", - "phpstan/phpstan": "^1.4.1", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5.20 || ^8.5 || ^9.0", - "squizlabs/php_codesniffer": "^3.0", - "symfony/phpunit-bridge": "^6.1", - "vimeo/psalm": "^4.4" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Common\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" - }, - { - "name": "Jonathan Wage", - "email": "jonwage@gmail.com" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" - }, - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" - } - ], - "description": "PHP Doctrine Common project is a library that provides additional functionality that other Doctrine projects depend on such as better reflection support, proxies and much more.", - "homepage": "https://www.doctrine-project.org/projects/common.html", - "keywords": [ - "common", - "doctrine", - "php" - ], - "support": { - "issues": "https://github.com/doctrine/common/issues", - "source": "https://github.com/doctrine/common/tree/3.5.0" - }, - "funding": [ - { - "url": "https://www.doctrine-project.org/sponsorship.html", - "type": "custom" - }, - { - "url": "https://www.patreon.com/phpdoctrine", - "type": "patreon" - }, - { - "url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcommon", - "type": "tidelift" - } - ], - "time": "2025-01-01T22:12:03+00:00" - }, { "name": "doctrine/dbal", - "version": "3.10.4", + "version": "4.4.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868" + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/63a46cb5aa6f60991186cc98c1d1b50c09311868", - "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", + "reference": "3d544473fb93f5c25b483ea4f4ce99f8c4d9d44c", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1|^2", - "php": "^7.4 || ^8.0", + "doctrine/deprecations": "^1.1.5", + "php": "^8.2", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, - "conflict": { - "doctrine/cache": "< 1.11" - }, "require-dev": { - "doctrine/cache": "^1.11|^2.0", "doctrine/coding-standard": "14.0.0", "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.1", + "jetbrains/phpstorm-stubs": "2023.2", "phpstan/phpstan": "2.1.30", + "phpstan/phpstan-phpunit": "2.0.7", "phpstan/phpstan-strict-rules": "^2", - "phpunit/phpunit": "9.6.29", + "phpunit/phpunit": "11.5.23", "slevomat/coding-standard": "8.24.0", "squizlabs/php_codesniffer": "4.0.0", - "symfony/cache": "^5.4|^6.0|^7.0|^8.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0|^8.0" + "symfony/cache": "^6.3.8|^7.0|^8.0", + "symfony/console": "^5.4|^6.3|^7.0|^8.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "bin": [ - "bin/doctrine-dbal" - ], "type": "library", "autoload": { "psr-4": { @@ -707,7 +514,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.4" + "source": "https://github.com/doctrine/dbal/tree/4.4.1" }, "funding": [ { @@ -723,7 +530,7 @@ "type": "tidelift" } ], - "time": "2025-11-29T10:46:08+00:00" + "time": "2025-12-04T10:11:03+00:00" }, { "name": "doctrine/deprecations", @@ -1412,61 +1219,48 @@ }, { "name": "doctrine/orm", - "version": "2.20.9", + "version": "3.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "87f1ba74e04c8694ca00099f3c64706ebac0b114" + "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/87f1ba74e04c8694ca00099f3c64706ebac0b114", - "reference": "87f1ba74e04c8694ca00099f3c64706ebac0b114", + "url": "https://api.github.com/repos/doctrine/orm/zipball/d4e9276e79602b1eb4c4029c6c999b0d93478e2f", + "reference": "d4e9276e79602b1eb4c4029c6c999b0d93478e2f", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.1", - "doctrine/common": "^3.0.3", - "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/collections": "^2.2", + "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^2 || ^3", - "doctrine/persistence": "^2.4 || ^3", + "doctrine/lexer": "^3", + "doctrine/persistence": "^3.3.1 || ^4", "ext-ctype": "*", - "php": "^7.1 || ^8.0", + "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0", - "symfony/polyfill-php72": "^1.23", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "doctrine/annotations": "<1.13 || >= 3.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0 || ^8.0", + "symfony/var-exporter": "^6.3.9 || ^7.0 || ^8.0" }, "require-dev": { - "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^14.0", - "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/extension-installer": "~1.1.0 || ^1.4", - "phpstan/phpstan": "~1.4.10 || 2.1.23", - "phpstan/phpstan-deprecation-rules": "^1 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "doctrine/coding-standard": "^14.0", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "2.1.23", + "phpstan/phpstan-deprecation-rules": "^2", + "phpunit/phpunit": "^10.5.0 || ^11.5", "psr/log": "^1 || ^2 || ^3", - "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0 || ^8.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", - "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, - "bin": [ - "bin/doctrine" - ], "type": "library", "autoload": { "psr-4": { @@ -1507,40 +1301,37 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.9" + "source": "https://github.com/doctrine/orm/tree/3.6.0" }, - "time": "2025-11-29T14:03:56+00:00" + "time": "2025-12-19T20:36:14+00:00" }, { "name": "doctrine/persistence", - "version": "3.4.3", + "version": "4.1.1", "source": { "type": "git", "url": "https://github.com/doctrine/persistence.git", - "reference": "d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0" + "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/persistence/zipball/d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0", - "reference": "d59e6ef7caffe6a30f4b6f9e9079a75f52c64ae0", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", + "reference": "b9c49ad3558bb77ef973f4e173f2e9c2eca9be09", "shasum": "" }, "require": { "doctrine/event-manager": "^1 || ^2", - "php": "^7.2 || ^8.0", + "php": "^8.1", "psr/cache": "^1.0 || ^2.0 || ^3.0" }, - "conflict": { - "doctrine/common": "<2.10" - }, "require-dev": { - "doctrine/coding-standard": "^12 || ^14", - "doctrine/common": "^3.0", - "phpstan/phpstan": "^1 || 2.1.30", - "phpstan/phpstan-phpunit": "^1 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8.5.38 || ^9.5", - "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0" + "doctrine/coding-standard": "^14", + "phpstan/phpstan": "2.1.30", + "phpstan/phpstan-phpunit": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.58 || ^12", + "symfony/cache": "^4.4 || ^5.4 || ^6.0 || ^7.0", + "symfony/finder": "^4.4 || ^5.4 || ^6.0 || ^7.0" }, "type": "library", "autoload": { @@ -1589,7 +1380,7 @@ ], "support": { "issues": "https://github.com/doctrine/persistence/issues", - "source": "https://github.com/doctrine/persistence/tree/3.4.3" + "source": "https://github.com/doctrine/persistence/tree/4.1.1" }, "funding": [ { @@ -1605,7 +1396,7 @@ "type": "tidelift" } ], - "time": "2025-10-21T15:21:39+00:00" + "time": "2025-10-16T20:13:18+00:00" }, { "name": "doctrine/sql-formatter", @@ -1664,22 +1455,22 @@ }, { "name": "easybill/zugferd-php", - "version": "v2.1.1", + "version": "v2.3.1", "source": { "type": "git", "url": "https://github.com/easybill/zugferd-php.git", - "reference": "376749138f5ecd216b73b5cdd5d4473f2a2d3252" + "reference": "fba2a504feb58ae2b3a19da5a0c051ce8fe13895" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/easybill/zugferd-php/zipball/376749138f5ecd216b73b5cdd5d4473f2a2d3252", - "reference": "376749138f5ecd216b73b5cdd5d4473f2a2d3252", + "url": "https://api.github.com/repos/easybill/zugferd-php/zipball/fba2a504feb58ae2b3a19da5a0c051ce8fe13895", + "reference": "fba2a504feb58ae2b3a19da5a0c051ce8fe13895", "shasum": "" }, "require": { "ext-dom": "*", "jms/serializer": "^3.16", - "php": "^8.1" + "php": "^8.2" }, "require-dev": { "ext-libxml": "*", @@ -1722,9 +1513,9 @@ ], "support": { "issues": "https://github.com/easybill/zugferd-php/issues", - "source": "https://github.com/easybill/zugferd-php/tree/v2.1.1" + "source": "https://github.com/easybill/zugferd-php/tree/v2.3.1" }, - "time": "2024-11-07T08:28:44+00:00" + "time": "2025-09-13T13:57:46+00:00" }, { "name": "egulias/email-validator", @@ -1795,29 +1586,26 @@ }, { "name": "endroid/qr-code", - "version": "4.8.5", + "version": "6.1.0", "source": { "type": "git", "url": "https://github.com/endroid/qr-code.git", - "reference": "0db25b506a8411a5e1644ebaa67123a6eb7b6a77" + "reference": "5a74873ba8873ddcc557d22755c914ac899563ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/endroid/qr-code/zipball/0db25b506a8411a5e1644ebaa67123a6eb7b6a77", - "reference": "0db25b506a8411a5e1644ebaa67123a6eb7b6a77", + "url": "https://api.github.com/repos/endroid/qr-code/zipball/5a74873ba8873ddcc557d22755c914ac899563ae", + "reference": "5a74873ba8873ddcc557d22755c914ac899563ae", "shasum": "" }, "require": { - "bacon/bacon-qr-code": "^2.0.5", - "php": "^8.1" - }, - "conflict": { - "khanamiryan/qrcode-detector-decoder": "^1.0.6" + "bacon/bacon-qr-code": "^3.0", + "php": "^8.4" }, "require-dev": { - "endroid/quality": "dev-master", + "endroid/quality": "dev-main", "ext-gd": "*", - "khanamiryan/qrcode-detector-decoder": "^1.0.4||^2.0.2", + "khanamiryan/qrcode-detector-decoder": "^2.0.3", "setasign/fpdf": "^1.8.2" }, "suggest": { @@ -1829,7 +1617,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-main": "6.x-dev" } }, "autoload": { @@ -1858,7 +1646,7 @@ ], "support": { "issues": "https://github.com/endroid/qr-code/issues", - "source": "https://github.com/endroid/qr-code/tree/4.8.5" + "source": "https://github.com/endroid/qr-code/tree/6.1.0" }, "funding": [ { @@ -1866,83 +1654,33 @@ "type": "github" } ], - "time": "2023-09-29T14:03:20+00:00" - }, - { - "name": "erusev/parsedown", - "version": "1.7.4", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3", - "reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35" - }, - "type": "library", - "autoload": { - "psr-0": { - "Parsedown": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com" - } - ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org", - "keywords": [ - "markdown", - "parser" - ], - "support": { - "issues": "https://github.com/erusev/parsedown/issues", - "source": "https://github.com/erusev/parsedown/tree/1.7.x" - }, - "time": "2019-12-30T22:54:17+00:00" + "time": "2025-11-25T10:47:45+00:00" }, { "name": "friendsofsymfony/rest-bundle", - "version": "3.8.0", + "version": "3.9.0-beta1", "source": { "type": "git", "url": "https://github.com/FriendsOfSymfony/FOSRestBundle.git", - "reference": "d24736896518bae817bf0de8a6b682cb6535044b" + "reference": "342632e21f53fdaff12d9d83234c08e2045ea0f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/d24736896518bae817bf0de8a6b682cb6535044b", - "reference": "d24736896518bae817bf0de8a6b682cb6535044b", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSRestBundle/zipball/342632e21f53fdaff12d9d83234c08e2045ea0f6", + "reference": "342632e21f53fdaff12d9d83234c08e2045ea0f6", "shasum": "" }, "require": { "php": "^7.4|^8.0", "symfony/config": "^5.4|^6.4|^7.0", - "symfony/dependency-injection": "^5.4|^6.4|^7.0", + "symfony/dependency-injection": "^5.4|^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.1|^3.0", - "symfony/event-dispatcher": "^5.4|^6.4|^7.0", - "symfony/framework-bundle": "^5.4|^6.4|^7.0", - "symfony/http-foundation": "^5.4|^6.4|^7.0", - "symfony/http-kernel": "^5.4|^6.4|^7.0", - "symfony/routing": "^5.4|^6.4|^7.0", - "symfony/security-core": "^5.4|^6.4|^7.0", + "symfony/event-dispatcher": "^5.4|^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^5.4|^6.4|^7.0|^8.0", + "symfony/http-foundation": "^5.4|^6.4|^7.0|^8.0", + "symfony/http-kernel": "^5.4|^6.4|^7.0|^8.0", + "symfony/routing": "^5.4|^6.4|^7.0|^8.0", + "symfony/security-core": "^5.4|^6.4|^7.0|^8.0", "willdurand/jsonp-callback-validator": "^1.0|^2.0", "willdurand/negotiation": "^2.0|^3.0" }, @@ -1960,19 +1698,19 @@ "psr/http-message": "^1.0", "psr/log": "^1.0|^2.0|^3.0", "sensio/framework-extra-bundle": "^6.1", - "symfony/asset": "^5.4|^6.4|^7.0", - "symfony/browser-kit": "^5.4|^6.4|^7.0", - "symfony/css-selector": "^5.4|^6.4|^7.0", - "symfony/expression-language": "^5.4|^6.4|^7.0", - "symfony/form": "^5.4|^6.4|^7.0", - "symfony/mime": "^5.4|^6.4|^7.0", - "symfony/phpunit-bridge": "^7.0.1", - "symfony/security-bundle": "^5.4|^6.4|^7.0", - "symfony/serializer": "^5.4|^6.4|^7.0", - "symfony/twig-bundle": "^5.4|^6.4|^7.0", - "symfony/validator": "^5.4|^6.4|^7.0", - "symfony/web-profiler-bundle": "^5.4|^6.4|^7.0", - "symfony/yaml": "^5.4|^6.4|^7.0" + "symfony/asset": "^5.4|^6.4|^7.0|^8.0", + "symfony/browser-kit": "^5.4|^6.4|^7.0|^8.0", + "symfony/css-selector": "^5.4|^6.4|^7.0|^8.0", + "symfony/expression-language": "^5.4|^6.4|^7.0|^8.0", + "symfony/form": "^5.4|^6.4|^7.0|^8.0", + "symfony/mime": "^5.4|^6.4|^7.0|^8.0", + "symfony/phpunit-bridge": "^7.0.1|^8.0", + "symfony/security-bundle": "^5.4|^6.4|^7.0|^8.0", + "symfony/serializer": "^5.4|^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^5.4|^6.4|^7.0|^8.0", + "symfony/validator": "^5.4|^6.4|^7.0|^8.0", + "symfony/web-profiler-bundle": "^5.4|^6.4|^7.0|^8.0", + "symfony/yaml": "^5.4|^6.4|^7.0|^8.0" }, "suggest": { "jms/serializer-bundle": "Add support for advanced serialization capabilities, recommended", @@ -2020,9 +1758,9 @@ ], "support": { "issues": "https://github.com/FriendsOfSymfony/FOSRestBundle/issues", - "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.8.0" + "source": "https://github.com/FriendsOfSymfony/FOSRestBundle/tree/3.9.0-beta1" }, - "time": "2024-11-04T08:41:36+00:00" + "time": "2025-12-22T13:26:35+00:00" }, { "name": "gedmo/doctrine-extensions", @@ -2798,16 +2536,16 @@ }, { "name": "league/csv", - "version": "9.27.1", + "version": "9.28.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797" + "reference": "6582ace29ae09ba5b07049d40ea13eb19c8b5073" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/26de738b8fccf785397d05ee2fc07b6cd8749797", - "reference": "26de738b8fccf785397d05ee2fc07b6cd8749797", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/6582ace29ae09ba5b07049d40ea13eb19c8b5073", + "reference": "6582ace29ae09ba5b07049d40ea13eb19c8b5073", "shasum": "" }, "require": { @@ -2817,14 +2555,14 @@ "require-dev": { "ext-dom": "*", "ext-xdebug": "*", - "friendsofphp/php-cs-fixer": "^3.75.0", - "phpbench/phpbench": "^1.4.1", - "phpstan/phpstan": "^1.12.27", + "friendsofphp/php-cs-fixer": "^3.92.3", + "phpbench/phpbench": "^1.4.3", + "phpstan/phpstan": "^1.12.32", "phpstan/phpstan-deprecation-rules": "^1.2.1", "phpstan/phpstan-phpunit": "^1.4.2", "phpstan/phpstan-strict-rules": "^1.6.2", - "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.3.6", - "symfony/var-dumper": "^6.4.8 || ^7.3.0" + "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.5.4", + "symfony/var-dumper": "^6.4.8 || ^7.4.0 || ^8.0" }, "suggest": { "ext-dom": "Required to use the XMLConverter and the HTMLConverter classes", @@ -2885,7 +2623,7 @@ "type": "github" } ], - "time": "2025-10-25T08:35:20+00:00" + "time": "2025-12-27T15:18:42+00:00" }, { "name": "lorenzo/pinky", @@ -2942,31 +2680,32 @@ }, { "name": "maennchen/zipstream-php", - "version": "3.1.1", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/maennchen/ZipStream-PHP.git", - "reference": "6187e9cc4493da94b9b63eb2315821552015fca9" + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/6187e9cc4493da94b9b63eb2315821552015fca9", - "reference": "6187e9cc4493da94b9b63eb2315821552015fca9", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/682f1098a8fddbaf43edac2306a691c7ad508ec5", + "reference": "682f1098a8fddbaf43edac2306a691c7ad508ec5", "shasum": "" }, "require": { "ext-mbstring": "*", "ext-zlib": "*", - "php-64bit": "^8.1" + "php-64bit": "^8.3" }, "require-dev": { + "brianium/paratest": "^7.7", "ext-zip": "*", - "friendsofphp/php-cs-fixer": "^3.16", + "friendsofphp/php-cs-fixer": "^3.86", "guzzlehttp/guzzle": "^7.5", "mikey179/vfsstream": "^1.6", "php-coveralls/php-coveralls": "^2.5", - "phpunit/phpunit": "^10.0", - "vimeo/psalm": "^5.0" + "phpunit/phpunit": "^12.0", + "vimeo/psalm": "^6.0" }, "suggest": { "guzzlehttp/psr7": "^2.4", @@ -3007,7 +2746,7 @@ ], "support": { "issues": "https://github.com/maennchen/ZipStream-PHP/issues", - "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.1.1" + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.1" }, "funding": [ { @@ -3015,7 +2754,7 @@ "type": "github" } ], - "time": "2024-10-10T12:33:01+00:00" + "time": "2025-12-10T09:58:31+00:00" }, { "name": "markbaker/complex", @@ -3126,16 +2865,16 @@ }, { "name": "monolog/monolog", - "version": "3.9.0", + "version": "3.10.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", - "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/b321dd6749f0bf7189444158a3ce785cc16d69b0", + "reference": "b321dd6749f0bf7189444158a3ce785cc16d69b0", "shasum": "" }, "require": { @@ -3153,7 +2892,7 @@ "graylog2/gelf-php": "^1.4.2 || ^2.0", "guzzlehttp/guzzle": "^7.4.5", "guzzlehttp/psr7": "^2.2", - "mongodb/mongodb": "^1.8", + "mongodb/mongodb": "^1.8 || ^2.0", "php-amqplib/php-amqplib": "~2.4 || ^3", "php-console/php-console": "^3.1.8", "phpstan/phpstan": "^2", @@ -3213,7 +2952,7 @@ ], "support": { "issues": "https://github.com/Seldaek/monolog/issues", - "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + "source": "https://github.com/Seldaek/monolog/tree/3.10.0" }, "funding": [ { @@ -3225,7 +2964,7 @@ "type": "tidelift" } ], - "time": "2025-03-24T10:02:05+00:00" + "time": "2026-01-02T08:56:05+00:00" }, { "name": "mpdf/mpdf", @@ -3462,35 +3201,36 @@ }, { "name": "nelmio/api-doc-bundle", - "version": "v5.7.1", + "version": "v5.8.2", "source": { "type": "git", "url": "https://github.com/nelmio/NelmioApiDocBundle.git", - "reference": "772d26a9d940c9a8d173f75f0fdbaab47c1c87f2" + "reference": "b29ed29a460cc25dab91c2eb6a4f22fd4f31dd37" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/772d26a9d940c9a8d173f75f0fdbaab47c1c87f2", - "reference": "772d26a9d940c9a8d173f75f0fdbaab47c1c87f2", + "url": "https://api.github.com/repos/nelmio/NelmioApiDocBundle/zipball/b29ed29a460cc25dab91c2eb6a4f22fd4f31dd37", + "reference": "b29ed29a460cc25dab91c2eb6a4f22fd4f31dd37", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "phpdocumentor/reflection-docblock": "^5.0", "phpdocumentor/type-resolver": "^1.8.2", "psr/cache": "^1.0 || ^2.0 || ^3.0", "psr/container": "^1.0 || ^2.0", "psr/log": "^1.0 || ^2.0 || ^3.0", - "symfony/config": "^6.4 || ^7.1", - "symfony/console": "^6.4 || ^7.1", - "symfony/dependency-injection": "^6.4 || ^7.1", + "symfony/config": "^6.4 || ^7.2", + "symfony/console": "^6.4 || ^7.2", + "symfony/dependency-injection": "^6.4 || ^7.2", "symfony/deprecation-contracts": "^2.1 || ^3", - "symfony/framework-bundle": "^6.4 || ^7.1", - "symfony/http-foundation": "^6.4 || ^7.1", - "symfony/http-kernel": "^6.4 || ^7.1", - "symfony/options-resolver": "^6.4 || ^7.1", - "symfony/property-info": "^6.4 || ^7.1", - "symfony/routing": "^6.4 || ^7.1", + "symfony/framework-bundle": "^6.4 || ^7.2", + "symfony/http-foundation": "^6.4 || ^7.2", + "symfony/http-kernel": "^6.4 || ^7.2", + "symfony/options-resolver": "^6.4 || ^7.2", + "symfony/property-info": "^6.4 || ^7.2", + "symfony/routing": "^6.4 || ^7.2", + "symfony/type-info": "^7.2", "zircote/swagger-php": "^4.11.1 || ^5.0" }, "conflict": { @@ -3507,24 +3247,24 @@ "phpstan/phpstan-strict-rules": "^2.0", "phpstan/phpstan-symfony": "^2.0", "phpunit/phpunit": "^10.5", - "symfony/asset": "^6.4 || ^7.1", - "symfony/browser-kit": "^6.4 || ^7.1", - "symfony/cache": "^6.4 || ^7.1", - "symfony/dom-crawler": "^6.4 || ^7.1", - "symfony/expression-language": "^6.4 || ^7.1", - "symfony/finder": "^6.4 || ^7.1", - "symfony/form": "^6.4 || ^7.1", - "symfony/phpunit-bridge": "^6.4 || ^7.1", - "symfony/property-access": "^6.4 || ^7.1", - "symfony/security-csrf": "^6.4 || ^7.1", - "symfony/security-http": "^6.4 || ^7.1", - "symfony/serializer": "^6.4 || ^7.1", - "symfony/stopwatch": "^6.4 || ^7.1", - "symfony/templating": "^6.4 || ^7.1", - "symfony/translation": "^6.4 || ^7.1", - "symfony/twig-bundle": "^6.4 || ^7.1", - "symfony/uid": "^6.4 || ^7.1", - "symfony/validator": "^6.4 || ^7.1", + "symfony/asset": "^6.4 || ^7.2", + "symfony/browser-kit": "^6.4 || ^7.2", + "symfony/cache": "^6.4 || ^7.2", + "symfony/dom-crawler": "^6.4 || ^7.2", + "symfony/expression-language": "^6.4 || ^7.2", + "symfony/finder": "^6.4 || ^7.2", + "symfony/form": "^6.4 || ^7.2", + "symfony/phpunit-bridge": "^6.4 || ^7.2", + "symfony/property-access": "^6.4 || ^7.2", + "symfony/security-csrf": "^6.4 || ^7.2", + "symfony/security-http": "^6.4 || ^7.2", + "symfony/serializer": "^6.4 || ^7.2", + "symfony/stopwatch": "^6.4 || ^7.2", + "symfony/templating": "^6.4 || ^7.2", + "symfony/translation": "^6.4 || ^7.2", + "symfony/twig-bundle": "^6.4 || ^7.2", + "symfony/uid": "^6.4 || ^7.2", + "symfony/validator": "^6.4 || ^7.2", "willdurand/hateoas-bundle": "^2.7", "willdurand/negotiation": "^3.0" }, @@ -3573,7 +3313,7 @@ ], "support": { "issues": "https://github.com/nelmio/NelmioApiDocBundle/issues", - "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v5.7.1" + "source": "https://github.com/nelmio/NelmioApiDocBundle/tree/v5.8.2" }, "funding": [ { @@ -3581,7 +3321,7 @@ "type": "github" } ], - "time": "2025-11-13T10:32:15+00:00" + "time": "2025-11-28T10:30:41+00:00" }, { "name": "nelmio/cors-bundle", @@ -3772,16 +3512,16 @@ }, { "name": "openspout/openspout", - "version": "v4.25.0", + "version": "v4.32.0", "source": { "type": "git", "url": "https://github.com/openspout/openspout.git", - "reference": "519affe730d92e1598720a6467227fc28550f0e6" + "reference": "41f045c1f632e1474e15d4c7bc3abcb4a153563d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/openspout/openspout/zipball/519affe730d92e1598720a6467227fc28550f0e6", - "reference": "519affe730d92e1598720a6467227fc28550f0e6", + "url": "https://api.github.com/repos/openspout/openspout/zipball/41f045c1f632e1474e15d4c7bc3abcb4a153563d", + "reference": "41f045c1f632e1474e15d4c7bc3abcb4a153563d", "shasum": "" }, "require": { @@ -3791,17 +3531,17 @@ "ext-libxml": "*", "ext-xmlreader": "*", "ext-zip": "*", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0" + "php": "~8.3.0 || ~8.4.0 || ~8.5.0" }, "require-dev": { "ext-zlib": "*", - "friendsofphp/php-cs-fixer": "^3.64.0", - "infection/infection": "^0.29.6", - "phpbench/phpbench": "^1.3.1", - "phpstan/phpstan": "^1.12.4", - "phpstan/phpstan-phpunit": "^1.4.0", - "phpstan/phpstan-strict-rules": "^1.6.1", - "phpunit/phpunit": "^10.5.20 || ^11.3.6" + "friendsofphp/php-cs-fixer": "^3.86.0", + "infection/infection": "^0.31.2", + "phpbench/phpbench": "^1.4.1", + "phpstan/phpstan": "^2.1.22", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "phpunit/phpunit": "^12.3.7" }, "suggest": { "ext-iconv": "To handle non UTF-8 CSV files (if \"php-mbstring\" is not already installed or is too limited)", @@ -3849,7 +3589,7 @@ ], "support": { "issues": "https://github.com/openspout/openspout/issues", - "source": "https://github.com/openspout/openspout/tree/v4.25.0" + "source": "https://github.com/openspout/openspout/tree/v4.32.0" }, "funding": [ { @@ -3861,36 +3601,35 @@ "type": "github" } ], - "time": "2024-09-24T09:03:42+00:00" + "time": "2025-09-03T16:03:54+00:00" }, { "name": "pagerfanta/pagerfanta", - "version": "v3.8.0", + "version": "v4.7.2", "source": { "type": "git", "url": "https://github.com/BabDev/Pagerfanta.git", - "reference": "a07c84296e491add39d103b812129de77610c33b" + "reference": "9320a542e1ed8d1a099a3d380685870e8bb5d553" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/BabDev/Pagerfanta/zipball/a07c84296e491add39d103b812129de77610c33b", - "reference": "a07c84296e491add39d103b812129de77610c33b", + "url": "https://api.github.com/repos/BabDev/Pagerfanta/zipball/9320a542e1ed8d1a099a3d380685870e8bb5d553", + "reference": "9320a542e1ed8d1a099a3d380685870e8bb5d553", "shasum": "" }, "require": { "ext-json": "*", - "php": "^7.4 || ^8.0", - "symfony/deprecation-contracts": "^2.1 || ^3.0", - "symfony/polyfill-php80": "^1.15" + "php": "^8.1", + "symfony/deprecation-contracts": "^2.1 || ^3.0" }, "conflict": { "doctrine/collections": "<1.8", - "doctrine/dbal": "<3.1", - "doctrine/mongodb-odm": "<2.2.2", - "doctrine/orm": "<2.8", - "doctrine/phpcr-odm": "<1.5", - "ruflin/elastica": "<6.0", - "solarium/solarium": "<5.0", + "doctrine/dbal": "<3.5", + "doctrine/mongodb-odm": "<2.4", + "doctrine/orm": "<2.14", + "doctrine/phpcr-odm": "<1.7", + "ruflin/elastica": "<7.3", + "solarium/solarium": "<6.2", "twig/twig": "<2.13" }, "replace": { @@ -3905,22 +3644,21 @@ "pagerfanta/twig": "self.version" }, "require-dev": { - "dg/bypass-finals": "^1.3", - "doctrine/cache": "^1.11 || ^2.0", + "dg/bypass-finals": "^1.9", "doctrine/collections": "^1.8 || ^2.0", - "doctrine/dbal": "^3.1", - "doctrine/mongodb-odm": "^2.2.2", - "doctrine/orm": "^2.8", - "doctrine/phpcr-odm": "^1.5", - "jackalope/jackalope-doctrine-dbal": "^1.7.4", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "1.9.14", - "phpstan/phpstan-phpunit": "1.3.3", - "phpunit/phpunit": "9.6.7 || 10.1.0", - "rector/rector": "0.15.12", - "ruflin/elastica": "^6.0 || ^7.0", - "solarium/solarium": "^5.0 || ^6.0", - "symfony/cache": "^5.4 || ^6.0", + "doctrine/dbal": "^3.5 || ^4.0", + "doctrine/mongodb-odm": "^2.4", + "doctrine/orm": "^2.14 || ^3.0", + "doctrine/phpcr-odm": "^1.7 || ^2.0", + "jackalope/jackalope-doctrine-dbal": "^1.9 || ^2.0", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "2.1.31", + "phpstan/phpstan-phpunit": "2.0.7", + "phpunit/phpunit": "10.5.58", + "rector/rector": "2.2.3", + "ruflin/elastica": "^7.3 || ^8.0", + "solarium/solarium": "^6.2", + "symfony/cache": "^5.4 || ^6.3 || ^7.0", "twig/twig": "^2.13 || ^3.0" }, "suggest": { @@ -3956,7 +3694,7 @@ ], "support": { "issues": "https://github.com/BabDev/Pagerfanta/issues", - "source": "https://github.com/BabDev/Pagerfanta/tree/v3.8.0" + "source": "https://github.com/BabDev/Pagerfanta/tree/v4.7.2" }, "funding": [ { @@ -3964,28 +3702,30 @@ "type": "github" } ], - "time": "2023-04-15T16:39:36+00:00" + "time": "2025-10-12T17:35:33+00:00" }, { "name": "paragonie/constant_time_encoding", - "version": "v2.8.2", + "version": "v3.1.3", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226" + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/e30811f7bc69e4b5b6d5783e712c06c8eabf0226", - "reference": "e30811f7bc69e4b5b6d5783e712c06c8eabf0226", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", + "reference": "d5b01a39b3415c2cd581d3bd3a3575c1ebbd8e77", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "infection/infection": "^0", + "nikic/php-fuzzer": "^0", + "phpunit/phpunit": "^9|^10|^11", + "vimeo/psalm": "^4|^5|^6" }, "type": "library", "autoload": { @@ -4031,7 +3771,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2025-09-24T15:12:37+00:00" + "time": "2025-09-24T15:06:41+00:00" }, { "name": "paragonie/random_compat", @@ -4083,6 +3823,67 @@ }, "time": "2020-10-15T08:29:30+00:00" }, + { + "name": "parsedown/parsedown", + "version": "1.7.5", + "source": { + "type": "git", + "url": "https://github.com/parsedown/parsedown.git", + "reference": "6ca5690b0282544416897376abe056601847ddb3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/parsedown/parsedown/zipball/6ca5690b0282544416897376abe056601847ddb3", + "reference": "6ca5690b0282544416897376abe056601847ddb3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8|^5.7|^6.5|^7.5|^8.5|^9.6" + }, + "type": "library", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "https://erusev.com" + }, + { + "name": "Aidan Woods", + "email": "aidantwoods@gmail.com", + "homepage": "https://aidanwoods.com", + "role": "Developer" + }, + { + "name": "Damien Regad", + "email": "dregad@mantisbt.org", + "role": "Fork Maintainer" + } + ], + "description": "Parser for Markdown.", + "homepage": "https://parsedown.org", + "keywords": [ + "markdown", + "parser" + ], + "support": { + "issues": "https://github.com/parsedown/parsedown/issues", + "source": "https://github.com/parsedown/parsedown/tree/1.7.5" + }, + "time": "2025-11-29T19:20:59+00:00" + }, { "name": "phpdocumentor/reflection-common", "version": "2.2.0", @@ -5075,20 +4876,20 @@ }, { "name": "scheb/2fa-backup-code", - "version": "v6.13.1", + "version": "v7.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-backup-code.git", - "reference": "6dceeb5be0f6339d76f8e380ee09631c8bbebc7e" + "reference": "35f1ace4be7be2c10158d2bb8284208499111db8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/6dceeb5be0f6339d76f8e380ee09631c8bbebc7e", - "reference": "6dceeb5be0f6339d76f8e380ee09631c8bbebc7e", + "url": "https://api.github.com/repos/scheb/2fa-backup-code/zipball/35f1ace4be7be2c10158d2bb8284208499111db8", + "reference": "35f1ace4be7be2c10158d2bb8284208499111db8", "shasum": "" }, "require": { - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "scheb/2fa-bundle": "self.version" }, "type": "library", @@ -5118,40 +4919,40 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-backup-code/tree/v6.13.1" + "source": "https://github.com/scheb/2fa-backup-code/tree/v7.13.1" }, - "time": "2024-11-29T19:22:48+00:00" + "time": "2025-11-20T13:35:24+00:00" }, { "name": "scheb/2fa-bundle", - "version": "v6.13.1", + "version": "v7.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-bundle.git", - "reference": "8eadd57ebc2078ef273dca72b1ac4bd283812346" + "reference": "edcc14456b508aab37ec792cfc36793d04226784" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/8eadd57ebc2078ef273dca72b1ac4bd283812346", - "reference": "8eadd57ebc2078ef273dca72b1ac4bd283812346", + "url": "https://api.github.com/repos/scheb/2fa-bundle/zipball/edcc14456b508aab37ec792cfc36793d04226784", + "reference": "edcc14456b508aab37ec792cfc36793d04226784", "shasum": "" }, "require": { "ext-json": "*", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", - "symfony/config": "^5.4 || ^6.0", - "symfony/dependency-injection": "^5.4 || ^6.0", - "symfony/event-dispatcher": "^5.4 || ^6.0", - "symfony/framework-bundle": "^5.4 || ^6.0", - "symfony/http-foundation": "^5.4 || ^6.0", - "symfony/http-kernel": "^5.4 || ^6.0", - "symfony/property-access": "^5.4 || ^6.0", - "symfony/security-bundle": "^5.4 || ^6.0", - "symfony/twig-bundle": "^5.4 || ^6.0" + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "symfony/config": "^6.4 || ^7.0", + "symfony/dependency-injection": "^6.4 || ^7.0", + "symfony/event-dispatcher": "^6.4 || ^7.0", + "symfony/framework-bundle": "^6.4 || ^7.0", + "symfony/http-foundation": "^6.4 || ^7.0", + "symfony/http-kernel": "^6.4 || ^7.0", + "symfony/property-access": "^6.4 || ^7.0", + "symfony/security-bundle": "^6.4 || ^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/twig-bundle": "^6.4 || ^7.0" }, "conflict": { - "scheb/two-factor-bundle": "*", - "symfony/security-core": "^7" + "scheb/two-factor-bundle": "*" }, "suggest": { "scheb/2fa-backup-code": "Emergency codes when you have no access to other methods", @@ -5186,29 +4987,31 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-bundle/tree/v6.13.1" + "source": "https://github.com/scheb/2fa-bundle/tree/v7.13.1" }, - "time": "2024-11-29T19:29:49+00:00" + "time": "2025-12-18T15:29:07+00:00" }, { "name": "scheb/2fa-totp", - "version": "v6.13.1", + "version": "v7.13.1", "source": { "type": "git", "url": "https://github.com/scheb/2fa-totp.git", - "reference": "e72879c8e0aca5d21fdcfdecdaa98a1d1cad8612" + "reference": "89a0557e191cc3b49d138452e095e8b5fb703f40" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/scheb/2fa-totp/zipball/e72879c8e0aca5d21fdcfdecdaa98a1d1cad8612", - "reference": "e72879c8e0aca5d21fdcfdecdaa98a1d1cad8612", + "url": "https://api.github.com/repos/scheb/2fa-totp/zipball/89a0557e191cc3b49d138452e095e8b5fb703f40", + "reference": "89a0557e191cc3b49d138452e095e8b5fb703f40", "shasum": "" }, "require": { - "paragonie/constant_time_encoding": "^2.4", - "php": "~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", "scheb/2fa-bundle": "self.version", - "spomky-labs/otphp": "^10.0 || ^11.0" + "spomky-labs/otphp": "^11.0" + }, + "suggest": { + "symfony/validator": "Needed if you want to use the TOTP validator constraint" }, "type": "library", "autoload": { @@ -5237,9 +5040,9 @@ "two-step" ], "support": { - "source": "https://github.com/scheb/2fa-totp/tree/v6.13.1" + "source": "https://github.com/scheb/2fa-totp/tree/v7.13.1" }, - "time": "2024-11-29T19:22:48+00:00" + "time": "2025-12-04T15:55:14+00:00" }, { "name": "setasign/fpdf", @@ -5494,28 +5297,28 @@ }, { "name": "symfony/asset", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/asset.git", - "reference": "cfee7c0d64be113383db74a2fdd65d426b7f3aab" + "reference": "0f7bccb9ffa1f373cbd659774d90629b2773464f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/asset/zipball/cfee7c0d64be113383db74a2fdd65d426b7f3aab", - "reference": "cfee7c0d64be113383db74a2fdd65d426b7f3aab", + "url": "https://api.github.com/repos/symfony/asset/zipball/0f7bccb9ffa1f373cbd659774d90629b2773464f", + "reference": "0f7bccb9ffa1f373cbd659774d90629b2773464f", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/http-foundation": "<5.4" + "symfony/http-foundation": "<6.4" }, "require-dev": { - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0" + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5543,7 +5346,7 @@ "description": "Manages URL generation and versioning of web assets such as CSS stylesheets, JavaScript files and image files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/asset/tree/v6.4.24" + "source": "https://github.com/symfony/asset/tree/v7.4.0" }, "funding": [ { @@ -5563,35 +5366,38 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/cache", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "eb3272ed2daed13ed24816e862d73f73d995972a" + "reference": "642117d18bc56832e74b68235359ccefab03dd11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/eb3272ed2daed13ed24816e862d73f73d995972a", - "reference": "eb3272ed2daed13ed24816e862d73f73d995972a", + "url": "https://api.github.com/repos/symfony/cache/zipball/642117d18bc56832e74b68235359ccefab03dd11", + "reference": "642117d18bc56832e74b68235359ccefab03dd11", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.3.6|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "conflict": { - "doctrine/dbal": "<2.13.1", - "symfony/dependency-injection": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/var-dumper": "<5.4" + "doctrine/dbal": "<3.6", + "ext-redis": "<6.1", + "ext-relay": "<0.12.1", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" }, "provide": { "psr/cache-implementation": "2.0|3.0", @@ -5600,15 +5406,16 @@ }, "require-dev": { "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5643,7 +5450,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.30" + "source": "https://github.com/symfony/cache/tree/v7.4.3" }, "funding": [ { @@ -5663,7 +5470,7 @@ "type": "tidelift" } ], - "time": "2025-12-01T16:41:59+00:00" + "time": "2025-12-28T10:45:24+00:00" }, { "name": "symfony/cache-contracts", @@ -5743,20 +5550,20 @@ }, { "name": "symfony/clock", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/clock.git", - "reference": "fb2df4bc9e3037c4765ba7fd29e00167001a9b68" + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/clock/zipball/fb2df4bc9e3037c4765ba7fd29e00167001a9b68", - "reference": "fb2df4bc9e3037c4765ba7fd29e00167001a9b68", + "url": "https://api.github.com/repos/symfony/clock/zipball/9169f24776edde469914c1e7a1442a50f7a4e110", + "reference": "9169f24776edde469914c1e7a1442a50f7a4e110", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/clock": "^1.0", "symfony/polyfill-php83": "^1.28" }, @@ -5797,7 +5604,7 @@ "time" ], "support": { - "source": "https://github.com/symfony/clock/tree/v6.4.30" + "source": "https://github.com/symfony/clock/tree/v7.4.0" }, "funding": [ { @@ -5817,38 +5624,38 @@ "type": "tidelift" } ], - "time": "2025-11-11T21:24:34+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/config", - "version": "v6.4.28", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "15947c18ef3ddb0b2f4ec936b9e90e2520979f62" + "reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/15947c18ef3ddb0b2f4ec936b9e90e2520979f62", - "reference": "15947c18ef3ddb0b2f4ec936b9e90e2520979f62", + "url": "https://api.github.com/repos/symfony/config/zipball/800ce889e358a53a9678b3212b0c8cecd8c6aace", + "reference": "800ce889e358a53a9678b3212b0c8cecd8c6aace", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/filesystem": "^5.4|^6.0|^7.0", + "symfony/filesystem": "^7.1|^8.0", "symfony/polyfill-ctype": "~1.8" }, "conflict": { - "symfony/finder": "<5.4", + "symfony/finder": "<6.4", "symfony/service-contracts": "<2.5" }, "require-dev": { - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5876,7 +5683,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/v6.4.28" + "source": "https://github.com/symfony/config/tree/v7.4.3" }, "funding": [ { @@ -5896,51 +5703,51 @@ "type": "tidelift" } ], - "time": "2025-11-01T19:52:02+00:00" + "time": "2025-12-23T14:24:27+00:00" }, { "name": "symfony/console", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e" + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/1b2813049506b39eb3d7e64aff033fd5ca26c97e", - "reference": "1b2813049506b39eb3d7e64aff033fd5ca26c97e", + "url": "https://api.github.com/repos/symfony/console/zipball/732a9ca6cd9dfd940c639062d5edbde2f6727fb6", + "reference": "732a9ca6cd9dfd940c639062d5edbde2f6727fb6", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" + "symfony/string": "^7.2|^8.0" }, "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -5974,7 +5781,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.30" + "source": "https://github.com/symfony/console/tree/v7.4.3" }, "funding": [ { @@ -5994,24 +5801,24 @@ "type": "tidelift" } ], - "time": "2025-12-05T13:47:41+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761" + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/9b784413143701aa3c94ac1869a159a9e53e8761", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/ab862f478513e7ca2fe9ec117a6f01a8da6e1135", + "reference": "ab862f478513e7ca2fe9ec117a6f01a8da6e1135", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -6043,7 +5850,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.24" + "source": "https://github.com/symfony/css-selector/tree/v7.4.0" }, "funding": [ { @@ -6063,44 +5870,43 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-10-30T13:39:42+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "5328f994cbb0855ba25c3a54f4a31a279511640f" + "reference": "54122901b6d772e94f1e71a75e0533bc16563499" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/5328f994cbb0855ba25c3a54f4a31a279511640f", - "reference": "5328f994cbb0855ba25c3a54f4a31a279511640f", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/54122901b6d772e94f1e71a75e0533bc16563499", + "reference": "54122901b6d772e94f1e71a75e0533bc16563499", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/container": "^1.1|^2.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/service-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^6.4.20|^7.2.5" + "symfony/service-contracts": "^3.6", + "symfony/var-exporter": "^6.4.20|^7.2.5|^8.0" }, "conflict": { "ext-psr": "<1.1|>=2", - "symfony/config": "<6.1", - "symfony/finder": "<5.4", - "symfony/proxy-manager-bridge": "<6.3", - "symfony/yaml": "<5.4" + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" }, "provide": { "psr/container-implementation": "1.1|2.0", "symfony/service-implementation": "1.1|2.0|3.0" }, "require-dev": { - "symfony/config": "^6.1|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6128,7 +5934,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/v6.4.30" + "source": "https://github.com/symfony/dependency-injection/tree/v7.4.3" }, "funding": [ { @@ -6148,7 +5954,7 @@ "type": "tidelift" } ], - "time": "2025-12-07T09:29:59+00:00" + "time": "2025-12-28T10:55:46+00:00" }, { "name": "symfony/deprecation-contracts", @@ -6219,67 +6025,68 @@ }, { "name": "symfony/doctrine-bridge", - "version": "v6.4.26", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/doctrine-bridge.git", - "reference": "c14bb5a9125c411e73354954940e06b6e7fcc344" + "reference": "bd338ba08f5c47fe77e0a15e85ec3c5d070f9ceb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/c14bb5a9125c411e73354954940e06b6e7fcc344", - "reference": "c14bb5a9125c411e73354954940e06b6e7fcc344", + "url": "https://api.github.com/repos/symfony/doctrine-bridge/zipball/bd338ba08f5c47fe77e0a15e85ec3c5d070f9ceb", + "reference": "bd338ba08f5c47fe77e0a15e85ec3c5d070f9ceb", "shasum": "" }, "require": { - "doctrine/event-manager": "^1.2|^2", - "doctrine/persistence": "^2.5|^3.1|^4", - "php": ">=8.1", + "doctrine/event-manager": "^2", + "doctrine/persistence": "^3.1|^4", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "doctrine/dbal": "<2.13.1", + "doctrine/collections": "<1.8", + "doctrine/dbal": "<3.6", "doctrine/lexer": "<1.1", "doctrine/orm": "<2.15", - "symfony/cache": "<5.4", - "symfony/dependency-injection": "<6.2", - "symfony/form": "<5.4.38|>=6,<6.4.6|>=7,<7.0.6", - "symfony/http-foundation": "<6.3", - "symfony/http-kernel": "<6.2", - "symfony/lock": "<6.3", - "symfony/messenger": "<5.4", - "symfony/property-info": "<5.4", - "symfony/security-bundle": "<5.4", + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/form": "<6.4.6|>=7,<7.0.6", + "symfony/http-foundation": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/lock": "<6.4", + "symfony/messenger": "<6.4", + "symfony/property-info": "<6.4", + "symfony/security-bundle": "<6.4", "symfony/security-core": "<6.4", - "symfony/validator": "<6.4" + "symfony/validator": "<7.4" }, "require-dev": { - "doctrine/collections": "^1.0|^2.0", + "doctrine/collections": "^1.8|^2.0", "doctrine/data-fixtures": "^1.1|^2", - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "doctrine/orm": "^2.15|^3", "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^6.2|^7.0", - "symfony/doctrine-messenger": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4.38|^6.4.6|^7.0.6", - "symfony/http-kernel": "^6.3|^7.0", - "symfony/lock": "^6.3|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/proxy-manager-bridge": "^6.4", - "symfony/security-core": "^6.4|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/doctrine-messenger": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^7.2|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -6307,7 +6114,7 @@ "description": "Provides integration for Doctrine with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/doctrine-bridge/tree/v6.4.26" + "source": "https://github.com/symfony/doctrine-bridge/tree/v7.4.3" }, "funding": [ { @@ -6327,32 +6134,32 @@ "type": "tidelift" } ], - "time": "2025-09-26T15:07:38+00:00" + "time": "2025-12-22T13:47:05+00:00" }, { "name": "symfony/dotenv", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "924edbc9631b75302def0258ed1697948b17baf6" + "reference": "1658a4d34df028f3d93bcdd8e81f04423925a364" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/924edbc9631b75302def0258ed1697948b17baf6", - "reference": "924edbc9631b75302def0258ed1697948b17baf6", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/1658a4d34df028f3d93bcdd8e81f04423925a364", + "reference": "1658a4d34df028f3d93bcdd8e81f04423925a364", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/console": "<5.4", - "symfony/process": "<5.4" + "symfony/console": "<6.4", + "symfony/process": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6385,7 +6192,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.30" + "source": "https://github.com/symfony/dotenv/tree/v7.4.0" }, "funding": [ { @@ -6405,35 +6212,38 @@ "type": "tidelift" } ], - "time": "2025-11-14T17:33:48+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "41bedcaec5b72640b0ec2096547b75fda72ead6c" + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/41bedcaec5b72640b0ec2096547b75fda72ead6c", - "reference": "41bedcaec5b72640b0ec2096547b75fda72ead6c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/48be2b0653594eea32dcef130cca1c811dcf25c2", + "reference": "48be2b0653594eea32dcef130cca1c811dcf25c2", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "conflict": { "symfony/deprecation-contracts": "<2.5", "symfony/http-kernel": "<6.4" }, "require-dev": { + "symfony/console": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/serializer": "^5.4|^6.0|^7.0" + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" }, "bin": [ "Resources/bin/patch-type-declarations" @@ -6464,7 +6274,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.26" + "source": "https://github.com/symfony/error-handler/tree/v7.4.0" }, "funding": [ { @@ -6484,28 +6294,28 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-11-05T14:29:59+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.25", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b0cf3162020603587363f0551cd3be43958611ff" + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", - "reference": "b0cf3162020603587363f0551cd3be43958611ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9dddcddff1ef974ad87b3708e4b442dc38b2261d", + "reference": "9dddcddff1ef974ad87b3708e4b442dc38b2261d", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/event-dispatcher-contracts": "^2.5|^3" }, "conflict": { - "symfony/dependency-injection": "<5.4", + "symfony/dependency-injection": "<6.4", "symfony/service-contracts": "<2.5" }, "provide": { @@ -6514,13 +6324,14 @@ }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6548,7 +6359,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.4.0" }, "funding": [ { @@ -6568,7 +6379,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2025-10-28T09:38:46+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -6648,21 +6459,21 @@ }, { "name": "symfony/expression-language", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/expression-language.git", - "reference": "01906f3b379833b347de9abc8ddc326593e9122b" + "reference": "8b9bbbb8c71f79a09638f6ea77c531e511139efa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/expression-language/zipball/01906f3b379833b347de9abc8ddc326593e9122b", - "reference": "01906f3b379833b347de9abc8ddc326593e9122b", + "url": "https://api.github.com/repos/symfony/expression-language/zipball/8b9bbbb8c71f79a09638f6ea77c531e511139efa", + "reference": "8b9bbbb8c71f79a09638f6ea77c531e511139efa", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/cache": "^5.4|^6.0|^7.0", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0|^8.0", "symfony/deprecation-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3" }, @@ -6692,7 +6503,7 @@ "description": "Provides an engine that can compile and evaluate expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/expression-language/tree/v6.4.30" + "source": "https://github.com/symfony/expression-language/tree/v7.4.0" }, "funding": [ { @@ -6712,29 +6523,29 @@ "type": "tidelift" } ], - "time": "2025-11-09T10:02:06+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/filesystem", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789" + "reference": "d551b38811096d0be9c4691d406991b47c0c630a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789", - "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/d551b38811096d0be9c4691d406991b47c0c630a", + "reference": "d551b38811096d0be9c4691d406991b47c0c630a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.8" }, "require-dev": { - "symfony/process": "^5.4|^6.4|^7.0" + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6762,7 +6573,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.30" + "source": "https://github.com/symfony/filesystem/tree/v7.4.0" }, "funding": [ { @@ -6782,27 +6593,27 @@ "type": "tidelift" } ], - "time": "2025-11-26T14:43:45+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/finder", - "version": "v6.4.27", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b" + "reference": "fffe05569336549b20a1be64250b40516d6e8d06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/a1b6aa435d2fba50793b994a839c32b6064f063b", - "reference": "a1b6aa435d2fba50793b994a839c32b6064f063b", + "url": "https://api.github.com/repos/symfony/finder/zipball/fffe05569336549b20a1be64250b40516d6e8d06", + "reference": "fffe05569336549b20a1be64250b40516d6e8d06", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "require-dev": { - "symfony/filesystem": "^6.0|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -6830,7 +6641,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.27" + "source": "https://github.com/symfony/finder/tree/v7.4.3" }, "funding": [ { @@ -6850,7 +6661,7 @@ "type": "tidelift" } ], - "time": "2025-10-15T18:32:00+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/flex", @@ -6927,56 +6738,58 @@ }, { "name": "symfony/form", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "e6378bc56d5d56db65754a09c91a7cf7c35b44db" + "reference": "f7e147d3e57198122568f17909bc85266b0b2592" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/e6378bc56d5d56db65754a09c91a7cf7c35b44db", - "reference": "e6378bc56d5d56db65754a09c91a7cf7c35b44db", + "url": "https://api.github.com/repos/symfony/form/zipball/f7e147d3e57198122568f17909bc85266b0b2592", + "reference": "f7e147d3e57198122568f17909bc85266b0b2592", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/options-resolver": "^5.4|^6.0|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/options-resolver": "^7.3|^8.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "^1.21", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-access": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<5.4", - "symfony/dependency-injection": "<5.4", - "symfony/doctrine-bridge": "<5.4.21|>=6,<6.2.7", - "symfony/error-handler": "<5.4", - "symfony/framework-bundle": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/error-handler": "<6.4", + "symfony/framework-bundle": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/intl": "<7.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<6.3" + "symfony/twig-bridge": "<6.4" }, "require-dev": { "doctrine/collections": "^1.0|^2.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.2|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^7.4|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4.12|^7.1.5|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7004,7 +6817,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.30" + "source": "https://github.com/symfony/form/tree/v7.4.3" }, "funding": [ { @@ -7024,112 +6837,117 @@ "type": "tidelift" } ], - "time": "2025-12-05T07:26:17+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "3c212ec5cac588da8357f5c061194363a4e91010" + "reference": "df908e8f9e5f6cc3c9e0d0172e030a5c1c280582" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/3c212ec5cac588da8357f5c061194363a4e91010", - "reference": "3c212ec5cac588da8357f5c061194363a4e91010", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/df908e8f9e5f6cc3c9e0d0172e030a5c1c280582", + "reference": "df908e8f9e5f6cc3c9e0d0172e030a5c1c280582", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.4.12|^7.0", + "php": ">=8.2", + "symfony/cache": "^6.4.12|^7.0|^8.0", + "symfony/config": "^7.4.3|^8.0.3", + "symfony/dependency-injection": "^7.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.1|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4", + "symfony/error-handler": "^7.3|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^7.1|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^7.4|^8.0", + "symfony/http-kernel": "^7.4|^8.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/routing": "^6.4|^7.0" + "symfony/polyfill-php85": "^1.32", + "symfony/routing": "^7.4|^8.0" }, "conflict": { - "doctrine/annotations": "<1.13.1", "doctrine/persistence": "<1.3", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/asset": "<5.4", + "symfony/asset": "<6.4", "symfony/asset-mapper": "<6.4", - "symfony/clock": "<6.3", - "symfony/console": "<5.4|>=7.0", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", "symfony/dom-crawler": "<6.4", - "symfony/dotenv": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<6.3", - "symfony/lock": "<5.4", - "symfony/mailer": "<5.4", - "symfony/messenger": "<6.3", + "symfony/dotenv": "<6.4", + "symfony/form": "<7.4", + "symfony/http-client": "<6.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<7.4", "symfony/mime": "<6.4", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4", - "symfony/runtime": "<5.4.45|>=6.0,<6.4.13|>=7.0,<7.1.6", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", - "symfony/security-core": "<5.4", - "symfony/security-csrf": "<5.4", - "symfony/serializer": "<6.4", - "symfony/stopwatch": "<5.4", - "symfony/translation": "<6.4", - "symfony/twig-bridge": "<5.4", - "symfony/twig-bundle": "<5.4", + "symfony/security-core": "<6.4", + "symfony/security-csrf": "<7.2", + "symfony/serializer": "<7.2.5", + "symfony/stopwatch": "<6.4", + "symfony/translation": "<7.3", + "symfony/twig-bridge": "<6.4", + "symfony/twig-bundle": "<6.4", "symfony/validator": "<6.4", "symfony/web-profiler-bundle": "<6.4", - "symfony/workflow": "<6.4" + "symfony/webhook": "<7.2", + "symfony/workflow": "<7.4" }, "require-dev": { - "doctrine/annotations": "^1.13.1|^2", "doctrine/persistence": "^1.3|^2|^3", "dragonmantank/cron-expression": "^3.1", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", "seld/jsonlint": "^1.10", - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/asset-mapper": "^6.4|^7.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.2|^7.0", - "symfony/console": "^5.4.9|^6.0.9|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dom-crawler": "^6.4|^7.0", - "symfony/dotenv": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-client": "^6.3|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/mailer": "^5.4|^6.0|^7.0", - "symfony/messenger": "^6.3|^7.0", - "symfony/mime": "^6.4|^7.0", - "symfony/notifier": "^5.4|^6.0|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/asset-mapper": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/dotenv": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^7.4|^8.0", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/json-streamer": "^7.3|^8.0", + "symfony/lock": "^6.4|^7.0|^8.0", + "symfony/mailer": "^6.4|^7.0|^8.0", + "symfony/messenger": "^7.4|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/notifier": "^6.4|^7.0|^8.0", + "symfony/object-mapper": "^7.3|^8.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/scheduler": "^6.4.4|^7.0.4", - "symfony/security-bundle": "^5.4|^6.0|^7.0", - "symfony/semaphore": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "symfony/translation": "^6.4|^7.0", - "symfony/twig-bundle": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/workflow": "^6.4|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/twig": "^2.10|^3.0.4" + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/scheduler": "^6.4.4|^7.0.4|^8.0", + "symfony/security-bundle": "^6.4|^7.0|^8.0", + "symfony/semaphore": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.2.5|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^7.3|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^7.4|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/webhook": "^7.2|^8.0", + "symfony/workflow": "^7.4|^8.0", + "symfony/yaml": "^7.3|^8.0", + "twig/twig": "^3.12" }, "type": "symfony-bundle", "autoload": { @@ -7157,7 +6975,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/v6.4.30" + "source": "https://github.com/symfony/framework-bundle/tree/v7.4.3" }, "funding": [ { @@ -7177,24 +6995,24 @@ "type": "tidelift" } ], - "time": "2025-11-29T11:31:32+00:00" + "time": "2025-12-29T09:31:36+00:00" }, { "name": "symfony/http-client", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "a67de2002d72f76ce7c57f830c4df503febc8d77" + "reference": "d01dfac1e0dc99f18da48b18101c23ce57929616" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/a67de2002d72f76ce7c57f830c4df503febc8d77", - "reference": "a67de2002d72f76ce7c57f830c4df503febc8d77", + "url": "https://api.github.com/repos/symfony/http-client/zipball/d01dfac1e0dc99f18da48b18101c23ce57929616", + "reference": "d01dfac1e0dc99f18da48b18101c23ce57929616", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", @@ -7202,8 +7020,10 @@ "symfony/service-contracts": "^2.5|^3" }, "conflict": { + "amphp/amp": "<2.5", + "amphp/socket": "<1.1", "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.3" + "symfony/http-foundation": "<6.4" }, "provide": { "php-http/async-client-implementation": "*", @@ -7212,19 +7032,20 @@ "symfony/http-client-implementation": "3.0" }, "require-dev": { - "amphp/amp": "^2.5", - "amphp/http-client": "^4.2.1", - "amphp/http-tunnel": "^1.0", - "amphp/socket": "^1.1", + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", "guzzlehttp/promises": "^1.4|^2.0", "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7255,7 +7076,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v6.4.30" + "source": "https://github.com/symfony/http-client/tree/v7.4.3" }, "funding": [ { @@ -7275,7 +7096,7 @@ "type": "tidelift" } ], - "time": "2025-12-04T16:42:50+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/http-client-contracts", @@ -7357,36 +7178,37 @@ }, { "name": "symfony/http-foundation", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6" + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/0384c62b79d96e9b22d77bc1272c9e83342ba3a6", - "reference": "0384c62b79d96e9b22d77bc1272c9e83342ba3a6", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/a70c745d4cea48dbd609f4075e5f5cbce453bd52", + "reference": "a70c745d4cea48dbd609f4075e5f5cbce453bd52", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.1", - "symfony/polyfill-php83": "^1.27" + "symfony/polyfill-mbstring": "^1.1" }, "conflict": { + "doctrine/dbal": "<3.6", "symfony/cache": "<6.4.12|>=7.0,<7.1.5" }, "require-dev": { - "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/dbal": "^3.6|^4", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^6.4.12|^7.1.5", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4.12|^7.1.5|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7414,7 +7236,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.30" + "source": "https://github.com/symfony/http-foundation/tree/v7.4.3" }, "funding": [ { @@ -7434,77 +7256,78 @@ "type": "tidelift" } ], - "time": "2025-12-01T20:07:31+00:00" + "time": "2025-12-23T14:23:49+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "ceac681e74e824bbf90468eb231d40988d6d18a5" + "reference": "885211d4bed3f857b8c964011923528a55702aa5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ceac681e74e824bbf90468eb231d40988d6d18a5", - "reference": "ceac681e74e824bbf90468eb231d40988d6d18a5", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/885211d4bed3f857b8c964011923528a55702aa5", + "reference": "885211d4bed3f857b8c964011923528a55702aa5", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/error-handler": "^6.4|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^7.3|^8.0", + "symfony/http-foundation": "^7.4|^8.0", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/browser-kit": "<5.4", - "symfony/cache": "<5.4", - "symfony/config": "<6.1", - "symfony/console": "<5.4", + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", "symfony/dependency-injection": "<6.4", - "symfony/doctrine-bridge": "<5.4", - "symfony/form": "<5.4", - "symfony/http-client": "<5.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/flex": "<2.10", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/translation": "<5.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", "symfony/translation-contracts": "<2.5", - "symfony/twig-bridge": "<5.4", + "symfony/twig-bridge": "<6.4", "symfony/validator": "<6.4", - "symfony/var-dumper": "<6.3", - "twig/twig": "<2.13" + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" }, "provide": { "psr/log-implementation": "1.0|2.0|3.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.2|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/dom-crawler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4.5|^6.0.5|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.4|^7.0.4", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^7.1|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/serializer": "^7.1|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.4|^7.0", - "symfony/var-exporter": "^6.2|^7.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" }, "type": "library", "autoload": { @@ -7532,7 +7355,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/v6.4.30" + "source": "https://github.com/symfony/http-kernel/tree/v7.4.3" }, "funding": [ { @@ -7552,29 +7375,32 @@ "type": "tidelift" } ], - "time": "2025-12-07T15:49:34+00:00" + "time": "2025-12-31T08:43:57+00:00" }, { "name": "symfony/intl", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/intl.git", - "reference": "5f40c7141be52f7ee86c4a42dce2845e6fbe3c85" + "reference": "2fa074de6c7faa6b54f2891fc22708f42245ed5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/intl/zipball/5f40c7141be52f7ee86c4a42dce2845e6fbe3c85", - "reference": "5f40c7141be52f7ee86c4a42dce2845e6fbe3c85", + "url": "https://api.github.com/repos/symfony/intl/zipball/2fa074de6c7faa6b54f2891fc22708f42245ed5c", + "reference": "2fa074de6c7faa6b54f2891fc22708f42245ed5c", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/string": "<7.1" }, "require-dev": { - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7619,7 +7445,7 @@ "localization" ], "support": { - "source": "https://github.com/symfony/intl/tree/v6.4.30" + "source": "https://github.com/symfony/intl/tree/v7.4.0" }, "funding": [ { @@ -7639,43 +7465,43 @@ "type": "tidelift" } ], - "time": "2025-11-24T13:57:00+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.27", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "2f096718ed718996551f66e3a24e12b2ed027f95" + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/2f096718ed718996551f66e3a24e12b2ed027f95", - "reference": "2f096718ed718996551f66e3a24e12b2ed027f95", + "url": "https://api.github.com/repos/symfony/mailer/zipball/e472d35e230108231ccb7f51eb6b2100cac02ee4", + "reference": "e472d35e230108231ccb7f51eb6b2100cac02ee4", "shasum": "" }, "require": { "egulias/email-validator": "^2.1.10|^3|^4", - "php": ">=8.1", + "php": ">=8.2", "psr/event-dispatcher": "^1", "psr/log": "^1|^2|^3", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/mime": "^6.2|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/mime": "^7.2|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<5.4", - "symfony/messenger": "<6.2", - "symfony/mime": "<6.2", - "symfony/twig-bridge": "<6.2.1" + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/messenger": "^6.2|^7.0", - "symfony/twig-bridge": "^6.2|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -7703,7 +7529,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.27" + "source": "https://github.com/symfony/mailer/tree/v7.4.3" }, "funding": [ { @@ -7723,24 +7549,24 @@ "type": "tidelift" } ], - "time": "2025-10-24T13:29:09+00:00" + "time": "2025-12-16T08:02:06+00:00" }, { "name": "symfony/mime", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf" + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/69aeef5d2692bb7c18ce133b09f67b27260b7acf", - "reference": "69aeef5d2692bb7c18ce133b09f67b27260b7acf", + "url": "https://api.github.com/repos/symfony/mime/zipball/bdb02729471be5d047a3ac4a69068748f1a6be7a", + "reference": "bdb02729471be5d047a3ac4a69068748f1a6be7a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-intl-idn": "^1.10", "symfony/polyfill-mbstring": "^1.0" @@ -7749,18 +7575,18 @@ "egulias/email-validator": "~3.0.0", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/mailer": "<5.4", + "symfony/mailer": "<6.4", "symfony/serializer": "<6.4.3|>7.0,<7.0.3" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3.1|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.4|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3" + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0" }, "type": "library", "autoload": { @@ -7792,7 +7618,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.30" + "source": "https://github.com/symfony/mime/tree/v7.4.0" }, "funding": [ { @@ -7812,42 +7638,42 @@ "type": "tidelift" } ], - "time": "2025-11-16T09:57:53+00:00" + "time": "2025-11-16T10:14:42+00:00" }, { "name": "symfony/monolog-bridge", - "version": "v6.4.28", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/monolog-bridge.git", - "reference": "d2f4b68e3247cf44d93f48545c8c072a75c17e5b" + "reference": "189d16466ff83d9c51fad26382bf0beeb41bda21" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/d2f4b68e3247cf44d93f48545c8c072a75c17e5b", - "reference": "d2f4b68e3247cf44d93f48545c8c072a75c17e5b", + "url": "https://api.github.com/repos/symfony/monolog-bridge/zipball/189d16466ff83d9c51fad26382bf0beeb41bda21", + "reference": "189d16466ff83d9c51fad26382bf0beeb41bda21", "shasum": "" }, "require": { - "monolog/monolog": "^1.25.1|^2|^3", - "php": ">=8.1", + "monolog/monolog": "^3", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/console": "<5.4", - "symfony/http-foundation": "<5.4", - "symfony/security-core": "<5.4" + "symfony/console": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/security-core": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/mailer": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/security-core": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/mailer": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "symfony-bridge", "autoload": { @@ -7875,7 +7701,7 @@ "description": "Provides integration for Monolog with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/monolog-bridge/tree/v6.4.28" + "source": "https://github.com/symfony/monolog-bridge/tree/v7.4.0" }, "funding": [ { @@ -7895,7 +7721,7 @@ "type": "tidelift" } ], - "time": "2025-10-30T19:57:08+00:00" + "time": "2025-11-01T09:17:33+00:00" }, { "name": "symfony/monolog-bundle", @@ -7979,20 +7805,20 @@ }, { "name": "symfony/options-resolver", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" + "reference": "b38026df55197f9e39a44f3215788edf83187b80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", - "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b38026df55197f9e39a44f3215788edf83187b80", + "reference": "b38026df55197f9e39a44f3215788edf83187b80", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "type": "library", @@ -8026,7 +7852,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" + "source": "https://github.com/symfony/options-resolver/tree/v7.4.0" }, "funding": [ { @@ -8046,31 +7872,31 @@ "type": "tidelift" } ], - "time": "2025-11-12T13:06:53+00:00" + "time": "2025-11-12T15:39:26+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557" + "reference": "aa075ce6f54fe931f03c1e382597912f4fd94e1e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/dcab5ac87450aaed26483ba49c2ce86808da7557", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/aa075ce6f54fe931f03c1e382597912f4fd94e1e", + "reference": "aa075ce6f54fe931f03c1e382597912f4fd94e1e", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/security-core": "<5.4" + "symfony/security-core": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/security-core": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/security-core": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8102,7 +7928,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.24" + "source": "https://github.com/symfony/password-hasher/tree/v7.4.0" }, "funding": [ { @@ -8122,20 +7948,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-13T16:46:49+00:00" }, { - "name": "symfony/polyfill-php83", + "name": "symfony/polyfill-php85", "version": "v1.33.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", - "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", + "reference": "d4e5fcd4ab3d998ab16c0db48e6cbb9a01993f91", "shasum": "" }, "require": { @@ -8153,7 +7979,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Php83\\": "" + "Symfony\\Polyfill\\Php85\\": "" }, "classmap": [ "Resources/stubs" @@ -8173,7 +7999,7 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", "homepage": "https://symfony.com", "keywords": [ "compatibility", @@ -8182,7 +8008,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" + "source": "https://github.com/symfony/polyfill-php85/tree/v1.33.0" }, "funding": [ { @@ -8202,104 +8028,24 @@ "type": "tidelift" } ], - "time": "2025-07-08T02:45:35+00:00" - }, - { - "name": "symfony/polyfill-php84", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-php84.git", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php84/zipball/d8ced4d875142b6a7426000426b8abc631d6b191", - "reference": "d8ced4d875142b6a7426000426b8abc631d6b191", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php84\\": "" - }, - "classmap": [ - "Resources/stubs" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill backporting some PHP 8.4+ features to lower PHP versions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-php84/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-06-24T13:30:11+00:00" + "time": "2025-06-23T16:12:55+00:00" }, { "name": "symfony/process", - "version": "v6.4.26", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8" + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/48bad913268c8cafabbf7034b39c8bb24fbc5ab8", - "reference": "48bad913268c8cafabbf7034b39c8bb24fbc5ab8", + "url": "https://api.github.com/repos/symfony/process/zipball/2f8e1a6cdf590ca63715da4d3a7a3327404a523f", + "reference": "2f8e1a6cdf590ca63715da4d3a7a3327404a523f", "shasum": "" }, "require": { - "php": ">=8.1" + "php": ">=8.2" }, "type": "library", "autoload": { @@ -8327,7 +8073,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v6.4.26" + "source": "https://github.com/symfony/process/tree/v7.4.3" }, "funding": [ { @@ -8347,29 +8093,29 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { "name": "symfony/property-access", - "version": "v6.4.25", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168" + "reference": "30aff8455647be949fc2e8fcef2847d5a6743c98" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fedc771326d4978a7d3167fa009a509b06a2e168", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168", + "url": "https://api.github.com/repos/symfony/property-access/zipball/30aff8455647be949fc2e8fcef2847d5a6743c98", + "reference": "30aff8455647be949fc2e8fcef2847d5a6743c98", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/property-info": "^6.4.31|~7.3.9|^7.4.2|^8.0.3" }, "require-dev": { - "symfony/cache": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4.1|^7.0.1|^8.0" }, "type": "library", "autoload": { @@ -8408,7 +8154,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.25" + "source": "https://github.com/symfony/property-access/tree/v7.4.3" }, "funding": [ { @@ -8428,41 +8174,41 @@ "type": "tidelift" } ], - "time": "2025-08-12T15:42:57+00:00" + "time": "2025-12-18T10:35:58+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "13243e748cb77b3d2300c0bffa21c2d325dd6e98" + "reference": "ea62b28cd68fb36e252abd77de61e505a0f2a7b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/13243e748cb77b3d2300c0bffa21c2d325dd6e98", - "reference": "13243e748cb77b3d2300c0bffa21c2d325dd6e98", + "url": "https://api.github.com/repos/symfony/property-info/zipball/ea62b28cd68fb36e252abd77de61e505a0f2a7b1", + "reference": "ea62b28cd68fb36e252abd77de61e505a0f2a7b1", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/string": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/type-info": "~7.3.8|^7.4.1|^8.0.1" }, "conflict": { - "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<5.2", "phpdocumentor/type-resolver": "<1.5.1", - "symfony/cache": "<5.4", - "symfony/dependency-injection": "<5.4|>=6.0,<6.4", - "symfony/serializer": "<5.4" + "symfony/cache": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/serializer": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^5.2", "phpstan/phpdoc-parser": "^1.0|^2.0", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/serializer": "^5.4|^6.4|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8498,7 +8244,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.30" + "source": "https://github.com/symfony/property-info/tree/v7.4.3" }, "funding": [ { @@ -8518,30 +8264,29 @@ "type": "tidelift" } ], - "time": "2025-11-29T16:02:37+00:00" + "time": "2025-12-18T08:28:41+00:00" }, { "name": "symfony/rate-limiter", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/rate-limiter.git", - "reference": "15a9a10fd0f060243c88ce98d5c29e9cc4b886e7" + "reference": "5c6df5bc10308505bb0fa8d1388bc6bd8a628ba8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/15a9a10fd0f060243c88ce98d5c29e9cc4b886e7", - "reference": "15a9a10fd0f060243c88ce98d5c29e9cc4b886e7", + "url": "https://api.github.com/repos/symfony/rate-limiter/zipball/5c6df5bc10308505bb0fa8d1388bc6bd8a628ba8", + "reference": "5c6df5bc10308505bb0fa8d1388bc6bd8a628ba8", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/options-resolver": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/options-resolver": "^7.3|^8.0" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", - "symfony/lock": "^5.4|^6.0|^7.0" + "symfony/lock": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8573,7 +8318,7 @@ "rate-limiter" ], "support": { - "source": "https://github.com/symfony/rate-limiter/tree/v6.4.24" + "source": "https://github.com/symfony/rate-limiter/tree/v7.4.0" }, "funding": [ { @@ -8593,40 +8338,38 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/routing", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859" + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/ea50a13c2711eebcbb66b38ef6382e62e3262859", - "reference": "ea50a13c2711eebcbb66b38ef6382e62e3262859", + "url": "https://api.github.com/repos/symfony/routing/zipball/5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", + "reference": "5d3fd7adf8896c2fdb54e2f0f35b1bcbd9e45090", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { - "doctrine/annotations": "<1.12", - "symfony/config": "<6.2", - "symfony/dependency-injection": "<5.4", - "symfony/yaml": "<5.4" + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "psr/log": "^1|^2|^3", - "symfony/config": "^6.2|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8660,7 +8403,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.30" + "source": "https://github.com/symfony/routing/tree/v7.4.3" }, "funding": [ { @@ -8680,35 +8423,35 @@ "type": "tidelift" } ], - "time": "2025-11-22T09:51:35+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { "name": "symfony/runtime", - "version": "v6.4.30", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/runtime.git", - "reference": "fb3149ee85d3b639dd3e49ea9dda05656f0537e3" + "reference": "876f902a6cb6b26c003de244188c06b2ba1c172f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/runtime/zipball/fb3149ee85d3b639dd3e49ea9dda05656f0537e3", - "reference": "fb3149ee85d3b639dd3e49ea9dda05656f0537e3", + "url": "https://api.github.com/repos/symfony/runtime/zipball/876f902a6cb6b26c003de244188c06b2ba1c172f", + "reference": "876f902a6cb6b26c003de244188c06b2ba1c172f", "shasum": "" }, "require": { "composer-plugin-api": "^1.0|^2.0", - "php": ">=8.1" + "php": ">=8.2" }, "conflict": { - "symfony/dotenv": "<5.4" + "symfony/dotenv": "<6.4" }, "require-dev": { - "composer/composer": "^1.0.2|^2.0", - "symfony/console": "^5.4.9|^6.0.9|^7.0", - "symfony/dotenv": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0" + "composer/composer": "^2.6", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dotenv": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "composer-plugin", "extra": { @@ -8743,7 +8486,7 @@ "runtime" ], "support": { - "source": "https://github.com/symfony/runtime/tree/v6.4.30" + "source": "https://github.com/symfony/runtime/tree/v7.4.1" }, "funding": [ { @@ -8763,75 +8506,71 @@ "type": "tidelift" } ], - "time": "2025-12-05T10:55:13+00:00" + "time": "2025-12-05T14:04:53+00:00" }, { "name": "symfony/security-bundle", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/security-bundle.git", - "reference": "508e67e68156cf3cb2b982504191b2ce34daa921" + "reference": "48a64e746857464a5e8fd7bab84b31c9ba967eb9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-bundle/zipball/508e67e68156cf3cb2b982504191b2ce34daa921", - "reference": "508e67e68156cf3cb2b982504191b2ce34daa921", + "url": "https://api.github.com/repos/symfony/security-bundle/zipball/48a64e746857464a5e8fd7bab84b31c9ba967eb9", + "reference": "48a64e746857464a5e8fd7bab84b31c9ba967eb9", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/clock": "^6.3|^7.0", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.4.11|^7.1.4", + "php": ">=8.2", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^6.4.11|^7.1.4|^8.0", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.2|^7.0", - "symfony/http-kernel": "^6.2", - "symfony/password-hasher": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.2|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/security-http": "^6.3.6|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/password-hasher": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.4|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/security-http": "^7.4|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/browser-kit": "<5.4", - "symfony/console": "<5.4", + "symfony/browser-kit": "<6.4", + "symfony/console": "<6.4", "symfony/framework-bundle": "<6.4", - "symfony/http-client": "<5.4", - "symfony/ldap": "<5.4", + "symfony/http-client": "<6.4", + "symfony/ldap": "<6.4", "symfony/serializer": "<6.4", - "symfony/twig-bundle": "<5.4", + "symfony/twig-bundle": "<6.4", "symfony/validator": "<6.4" }, "require-dev": { - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dom-crawler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/ldap": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/twig-bridge": "^5.4|^6.0|^7.0", - "symfony/twig-bundle": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/twig": "^2.13|^3.0.4", - "web-token/jwt-checker": "^3.1", - "web-token/jwt-signature-algorithm-ecdsa": "^3.1", - "web-token/jwt-signature-algorithm-eddsa": "^3.1", - "web-token/jwt-signature-algorithm-hmac": "^3.1", - "web-token/jwt-signature-algorithm-none": "^3.1", - "web-token/jwt-signature-algorithm-rsa": "^3.1" + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/dom-crawler": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/ldap": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", + "twig/twig": "^3.15", + "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "symfony-bundle", "autoload": { @@ -8859,7 +8598,7 @@ "description": "Provides a tight integration of the Security component into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-bundle/tree/v6.4.30" + "source": "https://github.com/symfony/security-bundle/tree/v7.4.0" }, "funding": [ { @@ -8879,49 +8618,50 @@ "type": "tidelift" } ], - "time": "2025-12-04T18:05:02+00:00" + "time": "2025-11-14T09:57:20+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.27", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "673018434b38e504eb04ca3c6d7e2e7c86735bfb" + "reference": "be0b8585f2d69b48a9b1a6372aa48d23c7e7eeb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/673018434b38e504eb04ca3c6d7e2e7c86735bfb", - "reference": "673018434b38e504eb04ca3c6d7e2e7c86735bfb", + "url": "https://api.github.com/repos/symfony/security-core/zipball/be0b8585f2d69b48a9b1a6372aa48d23c7e7eeb4", + "reference": "be0b8585f2d69b48a9b1a6372aa48d23c7e7eeb4", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher-contracts": "^2.5|^3", - "symfony/password-hasher": "^5.4|^6.0|^7.0", + "symfony/password-hasher": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/event-dispatcher": "<5.4", - "symfony/http-foundation": "<5.4", - "symfony/ldap": "<5.4", - "symfony/security-guard": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", - "symfony/validator": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/ldap": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/validator": "<6.4" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "psr/container": "^1.1|^2.0", "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/ldap": "^5.4|^6.0|^7.0", - "symfony/string": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/validator": "^6.4|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/event-dispatcher": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/ldap": "^6.4|^7.0|^8.0", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -8949,7 +8689,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.27" + "source": "https://github.com/symfony/security-core/tree/v7.4.3" }, "funding": [ { @@ -8969,31 +8709,33 @@ "type": "tidelift" } ], - "time": "2025-10-23T19:49:35+00:00" + "time": "2025-12-19T23:18:26+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.24", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7" + "reference": "d526fa61963d926e91c9fb22edf829d9f8793dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/9a1efc8c10b86bcedc9233affd10c716b54ca1b7", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/d526fa61963d926e91c9fb22edf829d9f8793dfe", + "reference": "d526fa61963d926e91c9fb22edf829d9f8793dfe", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/security-core": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/security-core": "^6.4|^7.0|^8.0" }, "conflict": { - "symfony/http-foundation": "<5.4" + "symfony/http-foundation": "<6.4" }, "require-dev": { - "symfony/http-foundation": "^5.4|^6.0|^7.0" + "psr/log": "^1|^2|^3", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9021,7 +8763,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.24" + "source": "https://github.com/symfony/security-csrf/tree/v7.4.3" }, "funding": [ { @@ -9041,51 +8783,51 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-12-23T15:24:11+00:00" }, { "name": "symfony/security-http", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/security-http.git", - "reference": "5705ae14ed77b38ac99990959d8c6dbcba86e513" + "reference": "72f3b3fa9f322c9579d5246895a09f945cc33e36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-http/zipball/5705ae14ed77b38ac99990959d8c6dbcba86e513", - "reference": "5705ae14ed77b38ac99990959d8c6dbcba86e513", + "url": "https://api.github.com/repos/symfony/security-http/zipball/72f3b3fa9f322c9579d5246895a09f945cc33e36", + "reference": "72f3b3fa9f322c9579d5246895a09f945cc33e36", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-foundation": "^6.2|^7.0", - "symfony/http-kernel": "^6.3|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/security-core": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/security-core": "^7.3|^8.0", "symfony/service-contracts": "^2.5|^3" }, "conflict": { - "symfony/clock": "<6.3", - "symfony/event-dispatcher": "<5.4.9|>=6,<6.0.9", + "symfony/clock": "<6.4", "symfony/http-client-contracts": "<3.0", - "symfony/security-bundle": "<5.4", - "symfony/security-csrf": "<5.4" + "symfony/security-bundle": "<6.4", + "symfony/security-csrf": "<6.4" }, "require-dev": { "psr/log": "^1|^2|^3", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/clock": "^6.3|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/clock": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^3.0", - "symfony/rate-limiter": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "web-token/jwt-checker": "^3.1", - "web-token/jwt-signature-algorithm-ecdsa": "^3.1" + "symfony/rate-limiter": "^6.4|^7.0|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "web-token/jwt-library": "^3.3.2|^4.0" }, "type": "library", "autoload": { @@ -9113,7 +8855,7 @@ "description": "Symfony Security Component - HTTP Integration", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-http/tree/v6.4.30" + "source": "https://github.com/symfony/security-http/tree/v7.4.3" }, "funding": [ { @@ -9133,61 +8875,62 @@ "type": "tidelift" } ], - "time": "2025-11-12T13:33:48+00:00" + "time": "2025-12-19T23:18:26+00:00" }, { "name": "symfony/serializer", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "d7976be554af097c788d7df25e10dd99facbfe65" + "reference": "af01e99d6fc63549063fb9e849ce1240cfef5c4a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/d7976be554af097c788d7df25e10dd99facbfe65", - "reference": "d7976be554af097c788d7df25e10dd99facbfe65", + "url": "https://api.github.com/repos/symfony/serializer/zipball/af01e99d6fc63549063fb9e849ce1240cfef5c4a", + "reference": "af01e99d6fc63549063fb9e849ce1240cfef5c4a", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "~1.8" + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-php84": "^1.30" }, "conflict": { - "doctrine/annotations": "<1.12", "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/dependency-injection": "<5.4", - "symfony/property-access": "<5.4", - "symfony/property-info": "<5.4.24|>=6,<6.2.11", - "symfony/uid": "<5.4", + "symfony/dependency-injection": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/uid": "<6.4", "symfony/validator": "<6.4", - "symfony/yaml": "<5.4" + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.12|^2", "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", "seld/jsonlint": "^1.10", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4.26|^6.3|^7.0", - "symfony/property-info": "^5.4.24|^6.2.11|^7.0", + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^7.2|^8.0", + "symfony/error-handler": "^6.4|^7.0|^8.0", + "symfony/filesystem": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/messenger": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3", - "symfony/uid": "^5.4|^6.0|^7.0", - "symfony/validator": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/type-info": "^7.1.8|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0", + "symfony/var-exporter": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9215,7 +8958,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/v6.4.30" + "source": "https://github.com/symfony/serializer/tree/v7.4.3" }, "funding": [ { @@ -9235,7 +8978,7 @@ "type": "tidelift" } ], - "time": "2025-11-12T13:46:18+00:00" + "time": "2025-12-23T14:50:43+00:00" }, { "name": "symfony/service-contracts", @@ -9326,20 +9069,20 @@ }, { "name": "symfony/stopwatch", - "version": "v6.4.24", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898" + "reference": "8a24af0a2e8a872fb745047180649b8418303084" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/b67e94e06a05d9572c2fa354483b3e13e3cb1898", - "reference": "b67e94e06a05d9572c2fa354483b3e13e3cb1898", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/8a24af0a2e8a872fb745047180649b8418303084", + "reference": "8a24af0a2e8a872fb745047180649b8418303084", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/service-contracts": "^2.5|^3" }, "type": "library", @@ -9368,7 +9111,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v6.4.24" + "source": "https://github.com/symfony/stopwatch/tree/v7.4.0" }, "funding": [ { @@ -9388,26 +9131,27 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-08-04T07:05:15+00:00" }, { "name": "symfony/string", - "version": "v6.4.30", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", - "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", + "url": "https://api.github.com/repos/symfony/string/zipball/d50e862cb0a0e0886f73ca1f31b865efbb795003", + "reference": "d50e862cb0a0e0886f73ca1f31b865efbb795003", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-grapheme": "~1.33", "symfony/polyfill-intl-normalizer": "~1.0", "symfony/polyfill-mbstring": "~1.0" }, @@ -9415,10 +9159,11 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" + "symfony/var-exporter": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9457,7 +9202,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.30" + "source": "https://github.com/symfony/string/tree/v7.4.0" }, "funding": [ { @@ -9477,55 +9222,56 @@ "type": "tidelift" } ], - "time": "2025-11-21T18:03:05+00:00" + "time": "2025-11-27T13:27:24+00:00" }, { "name": "symfony/translation", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39" + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/d1fdeefd0707d15eb150c04e8837bf0b15ebea39", - "reference": "d1fdeefd0707d15eb150c04e8837bf0b15ebea39", + "url": "https://api.github.com/repos/symfony/translation/zipball/7ef27c65d78886f7599fdd5c93d12c9243ecf44d", + "reference": "7ef27c65d78886f7599fdd5c93d12c9243ecf44d", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^2.5|^3.0" + "symfony/translation-contracts": "^2.5.3|^3.3" }, "conflict": { - "symfony/config": "<5.4", - "symfony/console": "<5.4", - "symfony/dependency-injection": "<5.4", + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", "symfony/http-client-contracts": "<2.5", - "symfony/http-kernel": "<5.4", + "symfony/http-kernel": "<6.4", "symfony/service-contracts": "<2.5", - "symfony/twig-bundle": "<5.4", - "symfony/yaml": "<5.4" + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" }, "provide": { "symfony/translation-implementation": "2.3|3.0" }, "require-dev": { - "nikic/php-parser": "^4.18|^5.0", + "nikic/php-parser": "^5.0", "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", "symfony/http-client-contracts": "^2.5|^3.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/service-contracts": "^2.5|^3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9556,7 +9302,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v6.4.30" + "source": "https://github.com/symfony/translation/tree/v7.4.3" }, "funding": [ { @@ -9576,7 +9322,7 @@ "type": "tidelift" } ], - "time": "2025-11-24T13:57:00+00:00" + "time": "2025-12-29T09:31:36+00:00" }, { "name": "symfony/translation-contracts", @@ -9662,68 +9408,70 @@ }, { "name": "symfony/twig-bridge", - "version": "v6.4.30", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34" + "reference": "43c922fce020060c65b0fd54bfd8def3b38949b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/d77a78c7fffaf7cb0158d28db824ba78d89a9f34", - "reference": "d77a78c7fffaf7cb0158d28db824ba78d89a9f34", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/43c922fce020060c65b0fd54bfd8def3b38949b6", + "reference": "43c922fce020060c65b0fd54bfd8def3b38949b6", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/translation-contracts": "^2.5|^3", - "twig/twig": "^2.13|^3.0.4" + "twig/twig": "^3.21" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", - "symfony/console": "<5.4", + "symfony/console": "<6.4", "symfony/form": "<6.4", - "symfony/http-foundation": "<5.4", + "symfony/http-foundation": "<6.4", "symfony/http-kernel": "<6.4", - "symfony/mime": "<6.2", + "symfony/mime": "<6.4", "symfony/serializer": "<6.4", - "symfony/translation": "<5.4", - "symfony/workflow": "<5.4" + "symfony/translation": "<6.4", + "symfony/workflow": "<6.4" }, "require-dev": { "egulias/email-validator": "^2.1.10|^3|^4", "league/html-to-markdown": "^5.0", "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/asset-mapper": "^6.3|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.30|~7.3.8|^7.4.1", - "symfony/html-sanitizer": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/mime": "^6.2|^7.0", + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/asset-mapper": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/emoji": "^7.1|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4.30|~7.3.8|^7.4.1|^8.0.1", + "symfony/html-sanitizer": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^7.3|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", "symfony/polyfill-intl-icu": "~1.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", "symfony/security-acl": "^2.8|^3.0", - "symfony/security-core": "^5.4|^6.0|^7.0", - "symfony/security-csrf": "^5.4|^6.0|^7.0", - "symfony/security-http": "^5.4|^6.0|^7.0", - "symfony/serializer": "^6.4.3|^7.0.3", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^6.1|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/workflow": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0", - "twig/cssinliner-extra": "^2.12|^3", - "twig/inky-extra": "^2.12|^3", - "twig/markdown-extra": "^2.12|^3" + "symfony/security-core": "^6.4|^7.0|^8.0", + "symfony/security-csrf": "^6.4|^7.0|^8.0", + "symfony/security-http": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4.3|^7.0.3|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/validator": "^6.4|^7.0|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/workflow": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0", + "twig/cssinliner-extra": "^3", + "twig/inky-extra": "^3", + "twig/markdown-extra": "^3" }, "type": "symfony-bridge", "autoload": { @@ -9751,7 +9499,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.30" + "source": "https://github.com/symfony/twig-bridge/tree/v7.4.3" }, "funding": [ { @@ -9771,47 +9519,49 @@ "type": "tidelift" } ], - "time": "2025-12-05T13:01:31+00:00" + "time": "2025-12-16T08:02:06+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.24", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba" + "reference": "9e1f5fd2668ed26c60d17d63f15fe270ed8da5e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/3b48b6e8225495c6d2438828982b4d219ca565ba", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/9e1f5fd2668ed26c60d17d63f15fe270ed8da5e6", + "reference": "9e1f5fd2668ed26c60d17d63f15fe270ed8da5e6", "shasum": "" }, "require": { "composer-runtime-api": ">=2.1", - "php": ">=8.1", - "symfony/config": "^6.1|^7.0", - "symfony/dependency-injection": "^6.1|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^6.2", - "symfony/twig-bridge": "^6.4", - "twig/twig": "^2.13|^3.0.4" + "php": ">=8.2", + "symfony/config": "^7.4|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/twig-bridge": "^7.3|^8.0", + "twig/twig": "^3.12" }, "conflict": { - "symfony/framework-bundle": "<5.4", - "symfony/translation": "<5.4" + "symfony/framework-bundle": "<6.4", + "symfony/translation": "<6.4" }, "require-dev": { - "symfony/asset": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^5.4|^6.0|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4|^6.0|^7.0", - "symfony/web-link": "^5.4|^6.0|^7.0", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/asset": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/form": "^6.4|^7.0|^8.0", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6", + "symfony/stopwatch": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4|^7.0|^8.0", + "symfony/web-link": "^6.4|^7.0|^8.0", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -9839,7 +9589,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.24" + "source": "https://github.com/symfony/twig-bundle/tree/v7.4.3" }, "funding": [ { @@ -9859,24 +9609,107 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-12-19T10:00:43+00:00" }, { - "name": "symfony/validator", - "version": "v6.4.30", + "name": "symfony/type-info", + "version": "v7.4.1", "source": { "type": "git", - "url": "https://github.com/symfony/validator.git", - "reference": "572dcc789ddf53174c61551aa5a3ec58d6a48b9b" + "url": "https://github.com/symfony/type-info.git", + "reference": "ac5ab66b21c758df71b7210cf1033d1ac807f202" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/validator/zipball/572dcc789ddf53174c61551aa5a3ec58d6a48b9b", - "reference": "572dcc789ddf53174c61551aa5a3ec58d6a48b9b", + "url": "https://api.github.com/repos/symfony/type-info/zipball/ac5ab66b21c758df71b7210cf1033d1ac807f202", + "reference": "ac5ab66b21c758df71b7210cf1033d1ac807f202", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "phpstan/phpdoc-parser": "<1.30" + }, + "require-dev": { + "phpstan/phpdoc-parser": "^1.30|^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\TypeInfo\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mathias Arlaud", + "email": "mathias.arlaud@gmail.com" + }, + { + "name": "Baptiste LEDUC", + "email": "baptiste.leduc@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Extracts PHP types information.", + "homepage": "https://symfony.com", + "keywords": [ + "PHPStan", + "phpdoc", + "symfony", + "type" + ], + "support": { + "source": "https://github.com/symfony/type-info/tree/v7.4.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-12-05T14:04:53+00:00" + }, + { + "name": "symfony/validator", + "version": "v7.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "9670bedf4c454b21d1e04606b6c227990da8bebe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/9670bedf4c454b21d1e04606b6c227990da8bebe", + "reference": "9670bedf4c454b21d1e04606b6c227990da8bebe", + "shasum": "" + }, + "require": { + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", @@ -9884,34 +9717,37 @@ "symfony/translation-contracts": "^2.5|^3" }, "conflict": { - "doctrine/annotations": "<1.13", "doctrine/lexer": "<1.1", - "symfony/dependency-injection": "<5.4", - "symfony/expression-language": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/intl": "<5.4", - "symfony/property-info": "<5.4", - "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", - "symfony/yaml": "<5.4" + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<7.0", + "symfony/expression-language": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/intl": "<6.4", + "symfony/property-info": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/var-exporter": "<6.4.25|>=7.0,<7.3.3", + "symfony/yaml": "<6.4" }, "require-dev": { - "doctrine/annotations": "^1.13|^2", "egulias/email-validator": "^2.1.10|^3|^4", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/intl": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/property-access": "^5.4|^6.0|^7.0", - "symfony/property-info": "^5.4|^6.0|^7.0", - "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", - "symfony/yaml": "^5.4|^6.0|^7.0" + "symfony/cache": "^6.4|^7.0|^8.0", + "symfony/config": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/expression-language": "^6.4|^7.0|^8.0", + "symfony/finder": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/http-foundation": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/intl": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/property-info": "^6.4|^7.0|^8.0", + "symfony/string": "^6.4|^7.0|^8.0", + "symfony/translation": "^6.4.3|^7.0.3|^8.0", + "symfony/type-info": "^7.1.8", + "symfony/yaml": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -9940,7 +9776,7 @@ "description": "Provides tools to validate values", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/validator/tree/v6.4.30" + "source": "https://github.com/symfony/validator/tree/v7.4.3" }, "funding": [ { @@ -9960,37 +9796,36 @@ "type": "tidelift" } ], - "time": "2025-12-05T09:41:49+00:00" + "time": "2025-12-27T17:05:22+00:00" }, { "name": "symfony/var-dumper", - "version": "v6.4.26", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" + "reference": "7e99bebcb3f90d8721890f2963463280848cba92" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/7e99bebcb3f90d8721890f2963463280848cba92", + "reference": "7e99bebcb3f90d8721890f2963463280848cba92", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^6.3|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/uid": "^5.4|^6.0|^7.0", - "twig/twig": "^2.13|^3.0.4" + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0", + "symfony/uid": "^6.4|^7.0|^8.0", + "twig/twig": "^3.12" }, "bin": [ "Resources/bin/var-dump-server" @@ -10028,7 +9863,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" + "source": "https://github.com/symfony/var-dumper/tree/v7.4.3" }, "funding": [ { @@ -10048,30 +9883,30 @@ "type": "tidelift" } ], - "time": "2025-09-25T15:37:27+00:00" + "time": "2025-12-18T07:04:31+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.26", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc" + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/466fcac5fa2e871f83d31173f80e9c2684743bfc", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/03a60f169c79a28513a78c967316fbc8bf17816f", + "reference": "03a60f169c79a28513a78c967316fbc8bf17816f", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" + "symfony/property-access": "^6.4|^7.0|^8.0", + "symfony/serializer": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -10109,7 +9944,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.26" + "source": "https://github.com/symfony/var-exporter/tree/v7.4.0" }, "funding": [ { @@ -10129,7 +9964,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T09:57:09+00:00" + "time": "2025-09-11T10:15:23+00:00" }, { "name": "symfony/webpack-encore-bundle", @@ -10209,28 +10044,28 @@ }, { "name": "symfony/yaml", - "version": "v6.4.30", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331" + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8207ae83da19ee3748d6d4f567b4d9a7c656e331", - "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331", + "url": "https://api.github.com/repos/symfony/yaml/zipball/24dd4de28d2e3988b311751ac49e684d783e2345", + "reference": "24dd4de28d2e3988b311751ac49e684d783e2345", "shasum": "" }, "require": { - "php": ">=8.1", + "php": ">=8.2", "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.4" + "symfony/console": "<6.4" }, "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0" + "symfony/console": "^6.4|^7.0|^8.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -10261,7 +10096,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.30" + "source": "https://github.com/symfony/yaml/tree/v7.4.1" }, "funding": [ { @@ -10281,7 +10116,7 @@ "type": "tidelift" } ], - "time": "2025-12-02T11:50:18+00:00" + "time": "2025-12-04T18:11:45+00:00" }, { "name": "tijsverkoyen/css-to-inline-styles", @@ -10763,23 +10598,23 @@ }, { "name": "webmozart/assert", - "version": "1.12.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" + "reference": "1b34b004e35a164bc5bb6ebd33c844b2d8069a54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/1b34b004e35a164bc5bb6ebd33c844b2d8069a54", + "reference": "1b34b004e35a164bc5bb6ebd33c844b2d8069a54", "shasum": "" }, "require": { "ext-ctype": "*", "ext-date": "*", "ext-filter": "*", - "php": "^7.2 || ^8.0" + "php": "^8.2" }, "suggest": { "ext-intl": "", @@ -10789,7 +10624,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.10-dev" + "dev-feature/2-0": "2.0-dev" } }, "autoload": { @@ -10805,6 +10640,10 @@ { "name": "Bernhard Schussek", "email": "bschussek@gmail.com" + }, + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com" } ], "description": "Assertions to validate method input/output with nice error messages.", @@ -10815,9 +10654,9 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.1" + "source": "https://github.com/webmozarts/assert/tree/2.0.0" }, - "time": "2025-10-29T15:56:20+00:00" + "time": "2025-12-16T21:36:00+00:00" }, { "name": "willdurand/jsonp-callback-validator", @@ -14093,27 +13932,28 @@ }, { "name": "symfony/browser-kit", - "version": "v6.4.28", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/browser-kit.git", - "reference": "067e301786bbb58048077fc10507aceb18226e23" + "reference": "d5b5c731005f224fbc25289587a8538e4f62c762" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/browser-kit/zipball/067e301786bbb58048077fc10507aceb18226e23", - "reference": "067e301786bbb58048077fc10507aceb18226e23", + "url": "https://api.github.com/repos/symfony/browser-kit/zipball/d5b5c731005f224fbc25289587a8538e4f62c762", + "reference": "d5b5c731005f224fbc25289587a8538e4f62c762", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/dom-crawler": "^5.4|^6.0|^7.0" + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/dom-crawler": "^6.4|^7.0|^8.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/mime": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0" + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/http-client": "^6.4|^7.0|^8.0", + "symfony/mime": "^6.4|^7.0|^8.0", + "symfony/process": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -14141,7 +13981,7 @@ "description": "Simulates the behavior of a web browser, allowing you to make requests, click on links and submit forms programmatically", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/browser-kit/tree/v6.4.28" + "source": "https://github.com/symfony/browser-kit/tree/v7.4.3" }, "funding": [ { @@ -14161,37 +14001,34 @@ "type": "tidelift" } ], - "time": "2025-10-16T22:35:35+00:00" + "time": "2025-12-16T08:02:06+00:00" }, { "name": "symfony/debug-bundle", - "version": "v6.4.27", + "version": "v7.4.0", "source": { "type": "git", "url": "https://github.com/symfony/debug-bundle.git", - "reference": "21a61c55192d558a6b81cdb12e8c010fc9474fe0" + "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/21a61c55192d558a6b81cdb12e8c010fc9474fe0", - "reference": "21a61c55192d558a6b81cdb12e8c010fc9474fe0", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/329383fb895353e3c8ab792cc35c4a7e7b17881b", + "reference": "329383fb895353e3c8ab792cc35c4a7e7b17881b", "shasum": "" }, "require": { + "composer-runtime-api": ">=2.1", "ext-xml": "*", - "php": ">=8.1", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/twig-bridge": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "conflict": { - "symfony/config": "<5.4", - "symfony/dependency-injection": "<5.4" + "php": ">=8.2", + "symfony/config": "^7.3|^8.0", + "symfony/dependency-injection": "^6.4|^7.0|^8.0", + "symfony/http-kernel": "^6.4|^7.0|^8.0", + "symfony/twig-bridge": "^6.4|^7.0|^8.0", + "symfony/var-dumper": "^6.4|^7.0|^8.0" }, "require-dev": { - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/web-profiler-bundle": "^5.4|^6.0|^7.0" + "symfony/web-profiler-bundle": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -14219,7 +14056,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/v6.4.27" + "source": "https://github.com/symfony/debug-bundle/tree/v7.4.0" }, "funding": [ { @@ -14239,30 +14076,31 @@ "type": "tidelift" } ], - "time": "2025-10-11T17:35:31+00:00" + "time": "2025-10-24T13:56:35+00:00" }, { "name": "symfony/dom-crawler", - "version": "v6.4.25", + "version": "v7.4.1", "source": { "type": "git", "url": "https://github.com/symfony/dom-crawler.git", - "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524" + "reference": "0c5e8f20c74c78172a8ee72b125909b505033597" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/976302990f9f2a6d4c07206836dd4ca77cae9524", - "reference": "976302990f9f2a6d4c07206836dd4ca77cae9524", + "url": "https://api.github.com/repos/symfony/dom-crawler/zipball/0c5e8f20c74c78172a8ee72b125909b505033597", + "reference": "0c5e8f20c74c78172a8ee72b125909b505033597", "shasum": "" }, "require": { "masterminds/html5": "^2.6", - "php": ">=8.1", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/css-selector": "^5.4|^6.0|^7.0" + "symfony/css-selector": "^6.4|^7.0|^8.0" }, "type": "library", "autoload": { @@ -14290,7 +14128,7 @@ "description": "Eases DOM navigation for HTML and XML documents", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dom-crawler/tree/v6.4.25" + "source": "https://github.com/symfony/dom-crawler/tree/v7.4.1" }, "funding": [ { @@ -14310,32 +14148,28 @@ "type": "tidelift" } ], - "time": "2025-08-05T18:56:08+00:00" + "time": "2025-12-06T15:47:47+00:00" }, { "name": "symfony/phpunit-bridge", - "version": "v6.4.26", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "406aa80401bf960e7a173a3ccf268ae82b6bc93f" + "reference": "f933e68bb9df29d08077a37e1515a23fea8562ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/406aa80401bf960e7a173a3ccf268ae82b6bc93f", - "reference": "406aa80401bf960e7a173a3ccf268ae82b6bc93f", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/f933e68bb9df29d08077a37e1515a23fea8562ab", + "reference": "f933e68bb9df29d08077a37e1515a23fea8562ab", "shasum": "" }, "require": { - "php": ">=7.1.3" - }, - "conflict": { - "phpunit/phpunit": "<7.5|9.1.2" + "php": ">=8.1.0" }, "require-dev": { - "symfony/deprecation-contracts": "^2.5|^3.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/polyfill-php81": "^1.27" + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4.3|^7.0.3|^8.0" }, "bin": [ "bin/simple-phpunit" @@ -14379,7 +14213,7 @@ "testing" ], "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v6.4.26" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.4.3" }, "funding": [ { @@ -14399,42 +14233,46 @@ "type": "tidelift" } ], - "time": "2025-09-12T08:37:02+00:00" + "time": "2025-12-09T15:33:45+00:00" }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.27", + "version": "v7.4.3", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "4c2ab411372e8bd854678cd7c81f1a9bfd6914aa" + "reference": "5220b59d06f6554658a0dc4d6bd4497a789e51dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c2ab411372e8bd854678cd7c81f1a9bfd6914aa", - "reference": "4c2ab411372e8bd854678cd7c81f1a9bfd6914aa", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/5220b59d06f6554658a0dc4d6bd4497a789e51dd", + "reference": "5220b59d06f6554658a0dc4d6bd4497a789e51dd", "shasum": "" }, "require": { - "php": ">=8.1", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/framework-bundle": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/routing": "^5.4|^6.0|^7.0", - "symfony/twig-bundle": "^5.4|^6.0", - "twig/twig": "^2.13|^3.0.4" + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^7.3|^8.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/framework-bundle": "^6.4.13|^7.1.6|^8.0", + "symfony/http-kernel": "^6.4.13|^7.1.6|^8.0", + "symfony/routing": "^6.4|^7.0|^8.0", + "symfony/twig-bundle": "^6.4|^7.0|^8.0", + "twig/twig": "^3.15" }, "conflict": { - "symfony/form": "<5.4", - "symfony/mailer": "<5.4", - "symfony/messenger": "<5.4", - "symfony/twig-bundle": ">=7.0" + "symfony/form": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/serializer": "<7.2", + "symfony/workflow": "<7.3" }, "require-dev": { - "symfony/browser-kit": "^5.4|^6.0|^7.0", - "symfony/console": "^5.4|^6.0|^7.0", - "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0" + "symfony/browser-kit": "^6.4|^7.0|^8.0", + "symfony/console": "^6.4|^7.0|^8.0", + "symfony/css-selector": "^6.4|^7.0|^8.0", + "symfony/runtime": "^6.4.13|^7.1.6|^8.0", + "symfony/stopwatch": "^6.4|^7.0|^8.0" }, "type": "symfony-bundle", "autoload": { @@ -14465,7 +14303,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.27" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v7.4.3" }, "funding": [ { @@ -14485,7 +14323,7 @@ "type": "tidelift" } ], - "time": "2025-10-05T13:55:43+00:00" + "time": "2025-12-27T17:05:22+00:00" }, { "name": "theseer/tokenizer", @@ -14540,11 +14378,13 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": { + "friendsofsymfony/rest-bundle": 10 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "8.1.*||8.2.*||8.3.*||8.4.*||8.5.*", + "php": "8.4.*||8.5.*", "ext-gd": "*", "ext-intl": "*", "ext-json": "*", @@ -14560,7 +14400,7 @@ "ext-simplexml": "*" }, "platform-overrides": { - "php": "8.1.3" + "php": "8.4.4" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/config/bundles.php b/config/bundles.php index 6b8d787c1..175893d5c 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -9,7 +9,7 @@ return [ Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], Symfony\Bundle\SecurityBundle\SecurityBundle::class => ['all' => true], - Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true, 'test' => true], + Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], DAMA\DoctrineTestBundle\DAMADoctrineTestBundle::class => ['test' => true], JMS\SerializerBundle\JMSSerializerBundle::class => ['all' => true], FOS\RestBundle\FOSRestBundle::class => ['all' => true], diff --git a/config/locales.php b/config/locales.php index 024797a25..764a8a3e9 100644 --- a/config/locales.php +++ b/config/locales.php @@ -3,2030 +3,1740 @@ [ 'date' => 'd‏/M‏/y', 'time' => 'h:mm a', - 'rtl' => true, 'translation' => true, ], 'bg' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'cs' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'cs_CZ' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'da' => [ 'date' => 'dd.MM.y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => true, ], 'da_DK' => [ 'date' => 'dd.MM.y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'da_GL' => [ 'date' => 'dd.MM.y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'de' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'de_AT' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'de_BE' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'de_CH' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'de_DE' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'de_IT' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'de_LI' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'de_LU' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'el' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'el_CY' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'el_GR' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'en_AE' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_AG' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_AI' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_AS' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_AT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_AU' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_BB' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_BE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_BI' => [ 'date' => 'M/d/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_BM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_BS' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_BW' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_BZ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CA' => [ 'date' => 'y-MM-dd', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_CC' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CH' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CK' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CX' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_CY' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_CZ' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_DE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_DK' => [ 'date' => 'dd/MM/y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'en_DM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_ER' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_ES' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_FI' => [ 'date' => 'dd/MM/y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'en_FJ' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_FK' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_FM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_FR' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_GB' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_GD' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_GG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_GH' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_GI' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_GM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_GS' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_GU' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_GY' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_HK' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_HU' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_ID' => [ 'date' => 'dd/MM/y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'en_IE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_IL' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_IM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_IN' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_IO' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_IT' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_JE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_JM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_KE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_KI' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_KN' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_KY' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_LC' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_LR' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_LS' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_MG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_MH' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_MO' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_MP' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_MS' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_MT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_MU' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_MV' => [ 'date' => 'd-M-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_MW' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_MY' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_NA' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_NF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NL' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NO' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NR' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NU' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_NZ' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_PG' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_PH' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_PK' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_PL' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_PN' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_PR' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_PT' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_PW' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_RO' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_RW' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SB' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_SC' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SD' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_SE' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SG' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_SH' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SI' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SK' => [ - 'date' => 'M/d/y', + 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SL' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_SS' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_SX' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_SZ' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_TC' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_TK' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_TO' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_TT' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_TV' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_TZ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_UG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_UM' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_US' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_VC' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_VG' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_VI' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_VU' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_WS' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_ZA' => [ 'date' => 'y/MM/dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'en_ZM' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'en_ZW' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'eo' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'es' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'es_AR' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_BO' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_BR' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'es_BZ' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'es_CL' => [ 'date' => 'dd-MM-y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_CO' => [ 'date' => 'd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_CR' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_CU' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_DO' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_EC' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_ES' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'es_GQ' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'es_GT' => [ 'date' => 'd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_HN' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_MX' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_NI' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_PA' => [ 'date' => 'MM/dd/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_PE' => [ 'date' => 'd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_PH' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_PR' => [ 'date' => 'MM/dd/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_PY' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_SV' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_US' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_UY' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'es_VE' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'eu' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'eu_ES' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fa' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => true, ], 'fa_AF' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => false, ], 'fa_IR' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => false, ], 'fi' => [ 'date' => 'd.M.y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => true, ], 'fi_FI' => [ 'date' => 'd.M.y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => false, ], 'fo' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'fo_DK' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fo_FO' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'fr_BE' => [ 'date' => 'd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_BF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_BI' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_BJ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_BL' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CA' => [ 'date' => 'y-MM-dd', 'time' => 'HH \'h\' mm', - 'rtl' => false, 'translation' => false, ], 'fr_CD' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CH' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CI' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_CM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_DJ' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_DZ' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_FR' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_GA' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_GF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_GN' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_GP' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_GQ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_HT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_KM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_LU' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MA' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MC' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_ML' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MQ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_MR' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_MU' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_NC' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_NE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_PF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_PM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_RE' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_RW' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_SC' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_SN' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_SY' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_TD' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_TG' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_TN' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_VU' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'fr_WF' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'fr_YT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'he' => [ 'date' => 'd.M.y', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => true, ], 'he_IL' => [ 'date' => 'd.M.y', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => false, ], 'hr' => [ 'date' => 'dd. MM. y.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'hr_BA' => [ 'date' => 'd. M. y.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'hr_HR' => [ 'date' => 'dd. MM. y.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'hu' => [ 'date' => 'y. MM. dd.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'hu_HU' => [ 'date' => 'y. MM. dd.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'id' => [ 'date' => 'dd/MM/y', 'time' => 'HH.mm', - 'rtl' => false, 'translation' => true, ], 'it' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'it_CH' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'it_IT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'it_SM' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'it_VA' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ja' => [ 'date' => 'y/MM/dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'ja_JP' => [ 'date' => 'y/MM/dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ko' => [ 'date' => 'y. M. d.', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'ko_CN' => [ 'date' => 'y. M. d.', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ko_KP' => [ 'date' => 'y. M. d.', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'ko_KR' => [ 'date' => 'y. M. d.', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'nb_NO' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'nl' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'nl_AW' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_BE' => [ 'date' => 'd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_BQ' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_CW' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_NL' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_SR' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'nl_SX' => [ 'date' => 'dd-MM-y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pa' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'pl' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'pl_PL' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'pt_AO' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_BR' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'pt_CH' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_CV' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_GQ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_GW' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_LU' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_MO' => [ 'date' => 'dd/MM/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'pt_MZ' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_PT' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_ST' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'pt_TL' => [ 'date' => 'dd/MM/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ro' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'ro_MD' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ro_RO' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'ru_BY' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru_KG' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru_KZ' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru_MD' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru_RU' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ru_UA' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'sk' => [ 'date' => 'd. M. y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'sk_SK' => [ 'date' => 'd. M. y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'sl' => [ 'date' => 'd. M. y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'sv' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'sv_AX' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'sv_FI' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'sv_SE' => [ 'date' => 'y-MM-dd', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'ta' => [ 'date' => 'd/M/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'tr' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'tr_CY' => [ 'date' => 'd.MM.y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => false, ], 'tr_TR' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'uk' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'uk_UA' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'vi' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'vi_VN' => [ 'date' => 'd/M/y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => false, ], 'zh_CN' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'zh_Hant' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'zh_Hant_TW' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], ]; \ No newline at end of file diff --git a/config/packages/assets.yaml b/config/packages/assets.yaml deleted file mode 100644 index 98263b8ab..000000000 --- a/config/packages/assets.yaml +++ /dev/null @@ -1,6 +0,0 @@ -framework: - assets: - json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' - packages: - avatars: - base_path: 'avatars' diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml deleted file mode 100644 index 8fd915824..000000000 --- a/config/packages/cache.yaml +++ /dev/null @@ -1,17 +0,0 @@ -framework: - cache: - #app: cache.adapter.redis - #default_redis_provider: redis://127.0.0.1:6379 - - #app: cache.adapter.memcached - #default_memcached_provider: 'memcached://localhost' - - # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) - #app: cache.adapter.apcu - - pools: - doctrine.result_cache_pool: - adapter: cache.app - - doctrine.system_cache_pool: - adapter: cache.system diff --git a/config/packages/dama_doctrine_test_bundle.yaml b/config/packages/dama_doctrine_test_bundle.yaml new file mode 100644 index 000000000..3482cbae1 --- /dev/null +++ b/config/packages/dama_doctrine_test_bundle.yaml @@ -0,0 +1,5 @@ +when@test: + dama_doctrine_test: + enable_static_connection: true + enable_static_meta_data_cache: true + enable_static_query_cache: true diff --git a/config/packages/debug.yaml b/config/packages/debug.yaml new file mode 100644 index 000000000..ad874afdd --- /dev/null +++ b/config/packages/debug.yaml @@ -0,0 +1,5 @@ +when@dev: + debug: + # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. + # See the "server:dump" command to start a new server. + dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" diff --git a/config/packages/doctrine.yaml b/config/packages/doctrine.yaml index 6fd3b3f18..31a75ed44 100644 --- a/config/packages/doctrine.yaml +++ b/config/packages/doctrine.yaml @@ -10,29 +10,31 @@ doctrine: default_connection: default connections: default: + profiling_collect_backtrace: '%kernel.debug%' + use_savepoints: true # existing migrations will fail if the schema filter is activated #schema_filter: ~^(?!(bundle_migration_|kimai2_sessions))~ - url: '%env(DATABASE_URL)%' + url: '%env(resolve:DATABASE_URL)%' driver: 'pdo_mysql' charset: utf8mb4 default_table_options: charset: utf8mb4 collation: utf8mb4_unicode_ci schema_manager_factory: doctrine.dbal.default_schema_manager_factory - types: datetime: App\Doctrine\UTCDateTimeType datetime_immutable: App\Doctrine\UTCDateTimeImmutableType orm: controller_resolver: - # FIXME this is causing a deprecation and needs to be changed - # auto_mapping: false - auto_mapping: true - auto_generate_proxy_classes: '%kernel.debug%' + auto_mapping: false + auto_generate_proxy_classes: true default_entity_manager: default - enable_lazy_ghost_objects: true + enable_native_lazy_objects: true entity_managers: default: + identity_generation_preferences: + Doctrine\DBAL\Platforms\PostgreSQLPlatform: identity + validate_xml_mapping: true report_fields_where_declared: true connection: default naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware @@ -56,17 +58,23 @@ when@test: connections: default: logging: false - use_savepoints: true when@prod: doctrine: orm: - metadata_cache_driver: - type: pool - pool: doctrine.system_cache_pool + auto_generate_proxy_classes: false + proxy_dir: '%kernel.build_dir%/doctrine/orm/Proxies' query_cache_driver: type: pool pool: doctrine.system_cache_pool result_cache_driver: type: pool pool: doctrine.result_cache_pool + +framework: + cache: + pools: + doctrine.result_cache_pool: + adapter: cache.app + doctrine.system_cache_pool: + adapter: cache.system diff --git a/config/packages/doctrine_migrations.yaml b/config/packages/doctrine_migrations.yaml index 99ee9ca3c..05ff6ba1b 100644 --- a/config/packages/doctrine_migrations.yaml +++ b/config/packages/doctrine_migrations.yaml @@ -1,8 +1,11 @@ doctrine_migrations: + migrations_paths: + # namespace is arbitrary but should be different from App\Migrations + # as migrations classes should NOT be autoloaded + 'DoctrineMigrations': '%kernel.project_dir%/migrations' + enable_profiler: false transactional: false storage: table_storage: table_name: 'migration_versions' - migrations_paths: - 'DoctrineMigrations': '%kernel.project_dir%/migrations' - custom_template: '%kernel.project_dir%/migrations/MigrationTemplate.txt' \ No newline at end of file + custom_template: '%kernel.project_dir%/migrations/MigrationTemplate.txt' diff --git a/config/packages/fos_rest.yaml b/config/packages/fos_rest.yaml index f65e4f35e..47cbdf20b 100644 --- a/config/packages/fos_rest.yaml +++ b/config/packages/fos_rest.yaml @@ -1,3 +1,4 @@ +# Read the documentation: https://fosrestbundle.readthedocs.io/en/3.x/ fos_rest: param_fetcher_listener: enabled: true diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index b798664ef..f6618d212 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -37,6 +37,9 @@ framework: php_errors: log: true + property_info: + with_constructor_extractor: true + mailer: dsn: '%env(MAILER_URL)%' diff --git a/config/packages/jms_serializer.yaml b/config/packages/jms_serializer.yaml index d12d2c37d..abc01faac 100644 --- a/config/packages/jms_serializer.yaml +++ b/config/packages/jms_serializer.yaml @@ -3,10 +3,6 @@ jms_serializer: datetime: default_format: 'Y-m-d\TH:i:sO' # DATE_ISO8601 visitors: - json_serialization: - options: - - JSON_UNESCAPED_SLASHES - - JSON_PRESERVE_ZERO_FRACTION xml_serialization: format_output: '%kernel.debug%' metadata: @@ -18,3 +14,20 @@ jms_serializer: excluded: [] property_naming: id: 'jms_serializer.identical_property_naming_strategy' + +when@prod: + jms_serializer: + visitors: + json_serialization: + options: + - JSON_UNESCAPED_SLASHES + - JSON_PRESERVE_ZERO_FRACTION + +when@dev: + jms_serializer: + visitors: + json_serialization: + options: + - JSON_PRETTY_PRINT + - JSON_UNESCAPED_SLASHES + - JSON_PRESERVE_ZERO_FRACTION diff --git a/config/packages/monolog.yaml b/config/packages/monolog.yaml index e55a948dd..0d54bb050 100644 --- a/config/packages/monolog.yaml +++ b/config/packages/monolog.yaml @@ -1,5 +1,50 @@ monolog: - channels: ["deprecation"] + channels: + - deprecation # Deprecations are logged in the dedicated "deprecation" channel when it exists + +when@dev: + monolog: + handlers: + main: + type: fingers_crossed + action_level: notice + handler: file_log + excluded_http_codes: + - {400: ['^/api/']} + - {401: ['^/api/']} + - 403 + - 404 + - 405 + channels: ["!event", "!deprecation"] + file_log: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + formatter: monolog.formatter.kimai + console: + type: console + process_psr_3_messages: false + channels: ["!event", "!doctrine", "!deprecation"] + deprecation: + type: stream + channels: ["deprecation"] + path: "%kernel.logs_dir%/deprecations.log" + formatter: monolog.formatter.deprecation + +when@test: + monolog: + handlers: + main: + type: fingers_crossed + action_level: error + handler: nested + excluded_http_codes: [404, 405] + channels: ["!event"] + nested: + type: stream + path: "%kernel.logs_dir%/%kernel.environment%.log" + level: debug + formatter: monolog.formatter.kimai when@prod: monolog: @@ -24,42 +69,3 @@ when@prod: type: console process_psr_3_messages: false channels: ["!event", "!doctrine", "!deprecation"] - -when@dev: - monolog: - handlers: - main: - type: fingers_crossed - action_level: notice - handler: file_log - excluded_http_codes: - - {400: ['^/api/']} - - {401: ['^/api/']} - - 403 - - 404 - - {405: ['/homepage$', '/login_check$', '/export/data$']} - channels: ["!event", "!deprecation"] - file_log: - type: stream - path: "%kernel.logs_dir%/%kernel.environment%.log" - level: debug - formatter: monolog.formatter.kimai - console: - type: console - process_psr_3_messages: false - channels: ["!event", "!doctrine", "!deprecation"] - deprecation: - type: stream - channels: ["deprecation"] - path: "%kernel.logs_dir%/deprecations.log" - formatter: monolog.formatter.deprecation - -when@test: - monolog: - handlers: - main: - type: stream - path: "%kernel.logs_dir%/%kernel.environment%.log" - level: info - channels: ["!event"] - formatter: monolog.formatter.kimai diff --git a/config/packages/nelmio_cors.yaml b/config/packages/nelmio_cors.yaml index d0cd7640d..c859f3d9a 100644 --- a/config/packages/nelmio_cors.yaml +++ b/config/packages/nelmio_cors.yaml @@ -17,7 +17,7 @@ nelmio_cors: '^/api/': # allow_origin: ['%env(CORS_ALLOW_ORIGIN)%'] allow_origin: ['*'] - allow_headers: ['Content-Type', 'Authorization', 'X-AUTH-USER', 'X-AUTH-TOKEN'] + allow_headers: ['Content-Type', 'Authorization'] allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE'] # expose_headers: ['Link'] max_age: 3600 diff --git a/config/packages/routing.yaml b/config/packages/routing.yaml index c45d1af92..d0d34c039 100644 --- a/config/packages/routing.yaml +++ b/config/packages/routing.yaml @@ -1,3 +1,6 @@ +parameters: + env(default_uri): 'http://localhost' + framework: router: utf8: true @@ -5,7 +8,7 @@ framework: # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands - #default_uri: http://localhost + default_uri: '%env(DEFAULT_URI)%' when@test: framework: diff --git a/config/packages/security.yaml b/config/packages/security.yaml index dd3f10efc..d9b03fc11 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -1,7 +1,8 @@ security: + # https://symfony.com/doc/current/security.html#registering-the-user-hashing-passwords password_hashers: App\Entity\User: auto - + # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider providers: chain_provider: chain: @@ -11,12 +12,11 @@ security: class: App\Entity\User kimai_ldap: id: App\Ldap\LdapUserProvider - firewalls: dev: + # Ensure dev tools and static assets are always allowed pattern: ^/(_(profiler|wdt)|css|images|js)/ security: false - api: access_token: token_handler: App\API\Authentication\AccessTokenHandler @@ -27,66 +27,52 @@ security: stateless: true remember_me: false provider: chain_provider - custom_authenticators: - - App\API\Authentication\TokenAuthenticator - secured_area: kimai_ldap: ~ pattern: ^/ user_checker: App\Security\UserChecker stateless: false - entry_point: form_login - custom_authenticators: - App\Saml\SamlAuthenticator - remember_me: name: KIMAI_REMEMBER secret: '%kernel.secret%' lifetime: 604800 path: / always_remember_me: true - # activate all configured user provider provider: chain_provider - form_login: check_path: security_check login_path: login enable_csrf: true - two_factor: auth_form_path: 2fa_login check_path: 2fa_login_check remember_me_sets_trusted: true - logout: path: logout target: homepage enable_csrf: false - login_throttling: max_attempts: 5 interval: '5 minutes' - login_link: check_route: link_login_check signature_properties: ['id'] lifetime: 900 max_uses: 3 - access_decision_manager: # only grants access if there is no voter denying access strategy: unanimous allow_if_all_abstain: false - role_hierarchy: ROLE_USER: ~ ROLE_TEAMLEAD: ROLE_USER ROLE_ADMIN: ROLE_TEAMLEAD ROLE_SUPER_ADMIN: ROLE_ADMIN - + # Note: Only the *first* matching rule is applied access_control: - {path: '^/auth/2fa', role: IS_AUTHENTICATED_2FA_IN_PROGRESS} - {path: '^/auth', roles: PUBLIC_ACCESS} @@ -99,13 +85,12 @@ security: - {path: '^/api', roles: IS_AUTHENTICATED} when@test: - # this configuration simplifies testing URLs protected by the security mechanism - # See https://symfony.com/doc/current/cookbook/testing/http_authentication.html security: password_hashers: + # Password hashers are resource-intensive by design to ensure security. + # In tests, it's safe to reduce their cost to improve performance. App\Entity\User: algorithm: auto - # see https://github.com/symfony/recipes/pull/1026 - cost: 4 # Lowest possible value for bcrypt - time_cost: 3 # Lowest possible value for argon - memory_cost: 10 # Lowest possible value for argon + cost: 4 # Lowest possible value for bcrypt + time_cost: 3 # Lowest possible value for argon + memory_cost: 10 # Lowest possible value for argon diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml index 90a442037..72961c8e1 100644 --- a/config/packages/twig.yaml +++ b/config/packages/twig.yaml @@ -1,9 +1,11 @@ twig: - debug: '%kernel.debug%' - strict_variables: '%kernel.debug%' + file_name_pattern: '*.twig' form_themes: - 'form/vertical.html.twig' - exception_controller: null paths: '%kernel.project_dir%/templates/bundles/TablerBundle': theme '%kernel.project_dir%/vendor/kevinpapst/tabler-bundle/templates': theme + +when@test: + twig: + strict_variables: true diff --git a/config/packages/web_profiler.yaml b/config/packages/web_profiler.yaml index 17893da18..0eac3c989 100644 --- a/config/packages/web_profiler.yaml +++ b/config/packages/web_profiler.yaml @@ -1,15 +1,13 @@ when@dev: web_profiler: toolbar: true - intercept_redirects: false framework: - profiler: { only_exceptions: false } + profiler: + collect_serializer_data: true when@test: - web_profiler: - toolbar: false - intercept_redirects: false - framework: - profiler: { collect: false } + profiler: + collect: false + collect_serializer_data: true diff --git a/config/packages/webpack_encore.yaml b/config/packages/webpack_encore.yaml index 3062278c6..cc50b572d 100644 --- a/config/packages/webpack_encore.yaml +++ b/config/packages/webpack_encore.yaml @@ -1,17 +1,45 @@ webpack_encore: - # The path where Encore is building the assets. - # This should match Encore.setOutputPath() in webpack.config.js. + # The path where Encore is building the assets - i.e. Encore.setOutputPath() output_path: '%kernel.project_dir%/public/build' # If multiple builds are defined (as shown below), you can disable the default build: # output_path: false - # if using Encore.enableIntegrityHashes() specify the crossorigin attribute value (default: false, or use 'anonymous' or 'use-credentials') - # crossorigin: 'anonymous' - - # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) - # Available in version 1.2 - cache: '%kernel.debug%' + # Set attributes that will be rendered on all script and link tags + script_attributes: + defer: true + # Uncomment (also under link_attributes) if using Turbo Drive + # https://turbo.hotwired.dev/handbook/drive#reloading-when-assets-change + # 'data-turbo-track': reload + # link_attributes: + # Uncomment if using Turbo Drive + # 'data-turbo-track': reload -when@dev: + # If using Encore.enableIntegrityHashes() and need the crossorigin attribute (default: false, or use 'anonymous' or 'use-credentials') + # crossorigin: 'anonymous' + + # Preload all rendered script and link tags automatically via the HTTP/2 Link header + # preload: true + + # Throw an exception if the entrypoints.json file is missing or an entry is missing from the data + # strict_mode: false + + # If you have multiple builds: + # builds: + # frontend: '%kernel.project_dir%/public/frontend/build' + + # pass the build name as the 3rd argument to the Twig functions + # {{ encore_entry_script_tags('entry1', null, 'frontend') }} + +framework: + assets: + json_manifest_path: '%kernel.project_dir%/public/build/manifest.json' + +when@prod: webpack_encore: - cache: false + # Cache the entrypoints.json (rebuild Symfony's cache when entrypoints.json changes) + # Available in version 1.2 + cache: true + +#when@test: +# webpack_encore: +# strict_mode: false diff --git a/config/routes.yaml b/config/routes.yaml index 51e42a569..dc42456ae 100644 --- a/config/routes.yaml +++ b/config/routes.yaml @@ -1,4 +1,14 @@ +# yaml-language-server: $schema=../vendor/symfony/routing/Loader/schema/routing.schema.json + +# This file is the entry point to configure the routes of your app. +# Methods with the #[Route] attribute are automatically imported. +# See also https://symfony.com/doc/current/routing.html + +# To list all registered routes, run the following command: +# bin/console debug:router + controllers: +# resource: routing.controllers resource: ../src/Controller/ type: attribute prefix: /{_locale} @@ -8,7 +18,8 @@ controllers: api.swagger_ui: path: /api/doc methods: GET - defaults: { _controller: nelmio_api_doc.controller.stoplight } + defaults: + _controller: nelmio_api_doc.controller.stoplight api: resource: ../src/API/ diff --git a/config/routes/dev/twig.yaml b/config/routes/dev/twig.yaml deleted file mode 100644 index 104f99d00..000000000 --- a/config/routes/dev/twig.yaml +++ /dev/null @@ -1,5 +0,0 @@ -_errors: - resource: '@FrameworkBundle/Resources/config/routing/errors.xml' - prefix: /{_locale}/_error - defaults: - _locale: '%locale%' diff --git a/config/routes/dev/web_profiler.yaml b/config/routes/dev/web_profiler.yaml deleted file mode 100644 index c82beff2f..000000000 --- a/config/routes/dev/web_profiler.yaml +++ /dev/null @@ -1,7 +0,0 @@ -web_profiler_wdt: - resource: '@WebProfilerBundle/Resources/config/routing/wdt.xml' - prefix: /_wdt - -web_profiler_profiler: - resource: '@WebProfilerBundle/Resources/config/routing/profiler.xml' - prefix: /_profiler diff --git a/config/routes/framework.yaml b/config/routes/framework.yaml new file mode 100644 index 000000000..dc0c8d442 --- /dev/null +++ b/config/routes/framework.yaml @@ -0,0 +1,6 @@ +when@dev: + _errors: + resource: '@FrameworkBundle/Resources/config/routing/errors.php' + prefix: /{_locale}/_error + defaults: + _locale: '%locale%' diff --git a/config/routes/security.yaml b/config/routes/security.yaml new file mode 100644 index 000000000..f853be15c --- /dev/null +++ b/config/routes/security.yaml @@ -0,0 +1,3 @@ +_security_logout: + resource: security.route_loader.logout + type: service diff --git a/config/routes/web_profiler.yaml b/config/routes/web_profiler.yaml new file mode 100644 index 000000000..b3b7b4b0e --- /dev/null +++ b/config/routes/web_profiler.yaml @@ -0,0 +1,8 @@ +when@dev: + web_profiler_wdt: + resource: '@WebProfilerBundle/Resources/config/routing/wdt.php' + prefix: /_wdt + + web_profiler_profiler: + resource: '@WebProfilerBundle/Resources/config/routing/profiler.php' + prefix: /_profiler diff --git a/config/services.yaml b/config/services.yaml index 57b64d43b..a66c0e174 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -1,3 +1,11 @@ +# yaml-language-server: $schema=../vendor/symfony/dependency-injection/Loader/schema/services.schema.json + +# This file is the entry point to configure your own services. +# Files in the packages/ subdirectory configure your dependencies. +# See also https://symfony.com/doc/current/service_container/import.html + +# Put parameters here that don't need to change on each machine where the app is deployed +# https://symfony.com/doc/current/best_practices.html#use-parameters-for-application-configuration parameters: locale: en # can be regenerated with: bin/console kimai:reset:locales @@ -6,8 +14,8 @@ parameters: services: # default configuration for services in *this* file _defaults: - autowire: true - autoconfigure: true + autowire: true # Automatically injects dependencies in your services. + autoconfigure: true # Automatically registers your services as commands, event subscribers, etc. public: false bind: $projectDirectory: '%kernel.project_dir%' @@ -16,12 +24,11 @@ services: # makes classes in src/ available to be used as services # this creates a service per class whose id is the fully-qualified class name App\: - resource: '../src/*' + resource: '../src/' exclude: - '../src/API/Model/' - '../src/DependencyInjection/' - '../src/Doctrine/Extensions/' - - '../src/Entity/' - '../src/Event/' - '../src/Export/Package/' - '../src/Export/Base/' @@ -35,6 +42,9 @@ services: - '../src/Kernel.php' - '../src/Constants.php' + # add more service definitions when explicit configuration is needed + # please note that last definitions always *replace* previous ones + # controllers are imported separately to make sure services can be injected # as action arguments even if you don't extend any base controller class App\Controller\: @@ -227,3 +237,9 @@ services: App\API\ViewHandler: arguments: ['@fos_rest.view_handler.default'] + + App\Validator\Constraints\TimesheetAllValidator: + arguments: ['%kimai.validator_timesheet%'] + + App\Validator\Constraints\QuickEntryTimesheetValidator: + arguments: ['%kimai.validator_timesheet%'] diff --git a/config/services_test.yaml b/config/services_test.yaml deleted file mode 100644 index 1c181ac12..000000000 --- a/config/services_test.yaml +++ /dev/null @@ -1,25 +0,0 @@ -parameters: - locale: en - kimai_locales: ['ar', 'cs', 'de', 'de_CH', 'da', 'en', 'eo', 'es', 'eu', 'fr', 'he', 'hu', 'it', 'ja', 'ko', 'nl', 'pl', 'pt_BR', 'ro', 'ru', 'sk', 'sv', 'tr', 'vi', 'zh_CN'] - -services: - _defaults: - public: true - - App\Configuration\SystemConfiguration: - arguments: ['@App\Configuration\ConfigurationService', "%kimai.config%"] - - # required for the importer command test - App\Repository\UserRepository: - class: Doctrine\ORM\EntityRepository - factory: ['@doctrine.orm.entity_manager', getRepository] - arguments: ['App\Entity\User'] - - # required for the importer command test - App\Importer\ImporterService: - public: true - arguments: ['@App\Customer\CustomerService', '@App\Project\ProjectService'] - - App\User\UserService: - public: true - arguments: ['@App\Repository\UserRepository', '@event_dispatcher', '@validator', '@App\Configuration\SystemConfiguration', '@security.user_password_hasher'] diff --git a/migrations/.gitignore b/migrations/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/migrations/Version20190510205245.php b/migrations/Version20190510205245.php index c06a78d61..fd6e163fb 100644 --- a/migrations/Version20190510205245.php +++ b/migrations/Version20190510205245.php @@ -28,13 +28,13 @@ class Version20190510205245 extends AbstractMigration $timesheetTags->addColumn('tag_id', 'integer', ['length' => 11, 'notnull' => true]); $timesheetTags->addIndex(['timesheet_id'], 'IDX_E3284EFEABDD46BE'); $timesheetTags->addIndex(['tag_id'], 'IDX_E3284EFEBAD26311'); - $timesheetTags->setPrimaryKey(['timesheet_id', 'tag_id']); + $this->addPrimaryKeyConstraint($timesheetTags, ['timesheet_id', 'tag_id']); $tags = $schema->createTable('kimai2_tags'); $tags->addColumn('id', 'integer', ['length' => 11, 'autoincrement' => true, 'notnull' => true]); $tags->addColumn('name', 'string', ['length' => 100, 'notnull' => true]); $tags->addUniqueIndex(['name'], 'UNIQ_27CAF54C5E237E06'); - $tags->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($tags, ['id']); } public function down(Schema $schema): void diff --git a/migrations/Version20190617100845.php b/migrations/Version20190617100845.php index 5349e6d49..f7a3162a1 100644 --- a/migrations/Version20190617100845.php +++ b/migrations/Version20190617100845.php @@ -34,7 +34,7 @@ final class Version20190617100845 extends AbstractMigration $timesheetMeta->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); $timesheetMeta->addColumn('value', 'string', ['notnull' => false, 'length' => 255]); $timesheetMeta->addColumn('visible', 'boolean', ['notnull' => false, 'default' => false]); - $timesheetMeta->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($timesheetMeta, ['id']); $timesheetMeta->addIndex(['timesheet_id'], 'IDX_CB606CBAABDD46BE'); $timesheetMeta->addUniqueIndex(['timesheet_id', 'name'], 'UNIQ_CB606CBAABDD46BE5E237E06'); $timesheetMeta->addForeignKeyConstraint('kimai2_timesheet', ['timesheet_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_CB606CBAABDD46BE'); @@ -45,7 +45,7 @@ final class Version20190617100845 extends AbstractMigration $customerMeta->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); $customerMeta->addColumn('value', 'string', ['notnull' => false, 'length' => 255]); $customerMeta->addColumn('visible', 'boolean', ['notnull' => false, 'default' => false]); - $customerMeta->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($customerMeta, ['id']); $customerMeta->addIndex(['customer_id'], 'IDX_A48A760F9395C3F3'); $customerMeta->addUniqueIndex(['customer_id', 'name'], 'UNIQ_A48A760F9395C3F35E237E06'); $customerMeta->addForeignKeyConstraint('kimai2_customers', ['customer_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_A48A760F9395C3F3'); @@ -56,7 +56,7 @@ final class Version20190617100845 extends AbstractMigration $projectMeta->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); $projectMeta->addColumn('value', 'string', ['notnull' => false, 'length' => 255]); $projectMeta->addColumn('visible', 'boolean', ['notnull' => false, 'default' => false]); - $projectMeta->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($projectMeta, ['id']); $projectMeta->addIndex(['project_id'], 'IDX_50536EF2166D1F9C'); $projectMeta->addUniqueIndex(['project_id', 'name'], 'UNIQ_50536EF2166D1F9C5E237E06'); $projectMeta->addForeignKeyConstraint('kimai2_projects', ['project_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_50536EF2166D1F9C'); @@ -67,7 +67,7 @@ final class Version20190617100845 extends AbstractMigration $activityMeta->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); $activityMeta->addColumn('value', 'string', ['notnull' => false, 'length' => 255]); $activityMeta->addColumn('visible', 'boolean', ['notnull' => false, 'default' => false]); - $activityMeta->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($activityMeta, ['id']); $activityMeta->addIndex(['activity_id'], 'IDX_A7C0A43D81C06096'); $activityMeta->addUniqueIndex(['activity_id', 'name'], 'UNIQ_A7C0A43D81C060965E237E06'); $activityMeta->addForeignKeyConstraint('kimai2_activities', ['activity_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_A7C0A43D81C06096'); diff --git a/migrations/Version20190730123324.php b/migrations/Version20190730123324.php index f19626c48..c8b5d32d4 100644 --- a/migrations/Version20190730123324.php +++ b/migrations/Version20190730123324.php @@ -32,7 +32,7 @@ final class Version20190730123324 extends AbstractMigration $teams->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); $teams->addColumn('name', 'string', ['notnull' => true, 'length' => 100]); $teams->addColumn('teamlead_id', 'integer', ['length' => 11, 'notnull' => true]); - $teams->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($teams, ['id']); $teams->addUniqueIndex(['name'], 'UNIQ_3BEDDC7F5E237E06'); $teams->addForeignKeyConstraint('kimai2_users', ['teamlead_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_3BEDDC7F8F7DE5D7'); @@ -41,21 +41,21 @@ final class Version20190730123324 extends AbstractMigration $userTeams->addColumn('team_id', 'integer', ['length' => 11, 'notnull' => true]); $userTeams->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_B5E92CF8A76ED395'); $userTeams->addForeignKeyConstraint('kimai2_teams', ['team_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_B5E92CF8296CD8AE'); - $userTeams->setPrimaryKey(['user_id', 'team_id']); + $this->addPrimaryKeyConstraint($userTeams, ['user_id', 'team_id']); $customerTeams = $schema->createTable('kimai2_customers_teams'); $customerTeams->addColumn('customer_id', 'integer', ['length' => 11, 'notnull' => true]); $customerTeams->addColumn('team_id', 'integer', ['length' => 11, 'notnull' => true]); $customerTeams->addForeignKeyConstraint('kimai2_customers', ['customer_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_50BD83889395C3F3'); $customerTeams->addForeignKeyConstraint('kimai2_teams', ['team_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_50BD8388296CD8AE'); - $customerTeams->setPrimaryKey(['customer_id', 'team_id']); + $this->addPrimaryKeyConstraint($customerTeams, ['customer_id', 'team_id']); $projectTeams = $schema->createTable('kimai2_projects_teams'); $projectTeams->addColumn('project_id', 'integer', ['length' => 11, 'notnull' => true]); $projectTeams->addColumn('team_id', 'integer', ['length' => 11, 'notnull' => true]); $projectTeams->addForeignKeyConstraint('kimai2_projects', ['project_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_9345D431166D1F9C'); $projectTeams->addForeignKeyConstraint('kimai2_teams', ['team_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_9345D431296CD8AE'); - $projectTeams->setPrimaryKey(['project_id', 'team_id']); + $this->addPrimaryKeyConstraint($projectTeams, ['project_id', 'team_id']); } public function down(Schema $schema): void diff --git a/migrations/Version20191108151534.php b/migrations/Version20191108151534.php index 5cd3e5a29..9ad5e0be0 100644 --- a/migrations/Version20191108151534.php +++ b/migrations/Version20191108151534.php @@ -31,7 +31,7 @@ final class Version20191108151534 extends AbstractMigration $roles = $schema->createTable('kimai2_roles'); $roles->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); $roles->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); - $roles->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($roles, ['id']); $roles->addUniqueIndex(['name'], 'roles_name'); $rolePermissions = $schema->createTable('kimai2_roles_permissions'); @@ -39,7 +39,7 @@ final class Version20191108151534 extends AbstractMigration $rolePermissions->addColumn('role_id', 'integer', ['length' => 11, 'notnull' => true]); $rolePermissions->addColumn('permission', 'string', ['notnull' => true, 'length' => 50]); $rolePermissions->addColumn('allowed', 'boolean', ['notnull' => true, 'default' => false]); - $rolePermissions->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($rolePermissions, ['id']); $rolePermissions->addUniqueIndex(['role_id', 'permission'], 'role_permission'); $rolePermissions->addForeignKeyConstraint('kimai2_roles', ['role_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_D263A3B8D60322AC'); } diff --git a/migrations/Version20200109102138.php b/migrations/Version20200109102138.php index c48336dbe..d2095803f 100644 --- a/migrations/Version20200109102138.php +++ b/migrations/Version20200109102138.php @@ -35,7 +35,7 @@ final class Version20200109102138 extends AbstractMigration $customerComment->addColumn('created_by_id', 'integer', ['notnull' => true]); $customerComment->addColumn('created_at', 'datetime', ['notnull' => true]); $customerComment->addColumn('pinned', 'boolean', ['notnull' => true, 'default' => false]); - $customerComment->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($customerComment, ['id']); $customerComment->addIndex(['customer_id'], 'IDX_A5B142D99395C3F3'); $customerComment->addForeignKeyConstraint('kimai2_customers', ['customer_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_A5B142D99395C3F3'); $customerComment->addForeignKeyConstraint('kimai2_users', ['created_by_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_A5B142D9B03A8386'); @@ -47,7 +47,7 @@ final class Version20200109102138 extends AbstractMigration $projectComment->addColumn('created_by_id', 'integer', ['notnull' => true]); $projectComment->addColumn('created_at', 'datetime', ['notnull' => true]); $projectComment->addColumn('pinned', 'boolean', ['notnull' => true, 'default' => false]); - $projectComment->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($projectComment, ['id']); $projectComment->addIndex(['project_id'], 'IDX_29A23638166D1F9C'); $projectComment->addForeignKeyConstraint('kimai2_projects', ['project_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_29A23638166D1F9C'); $projectComment->addForeignKeyConstraint('kimai2_users', ['created_by_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_29A23638B03A8386'); diff --git a/migrations/Version20200205115243.php b/migrations/Version20200205115243.php index 1a25f1d2d..1d7133e45 100644 --- a/migrations/Version20200205115243.php +++ b/migrations/Version20200205115243.php @@ -37,7 +37,7 @@ final class Version20200205115243 extends AbstractMigration $customerRates->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_82AB0AECA76ED395'); $customerRates->addForeignKeyConstraint('kimai2_customers', ['customer_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_82AB0AEC9395C3F3'); $customerRates->addUniqueIndex(['user_id', 'customer_id'], 'UNIQ_82AB0AECA76ED3959395C3F3'); - $customerRates->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($customerRates, ['id']); $projectRates = $schema->createTable('kimai2_projects_rates'); $projectRates->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); @@ -48,7 +48,7 @@ final class Version20200205115243 extends AbstractMigration $projectRates->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_41535D55A76ED395'); $projectRates->addForeignKeyConstraint('kimai2_projects', ['project_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_41535D55166D1F9C'); $projectRates->addUniqueIndex(['user_id', 'project_id'], 'UNIQ_41535D55A76ED395166D1F9C'); - $projectRates->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($projectRates, ['id']); $activityRates = $schema->createTable('kimai2_activities_rates'); $activityRates->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); @@ -59,7 +59,7 @@ final class Version20200205115243 extends AbstractMigration $activityRates->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_4A7F11BEA76ED395'); $activityRates->addForeignKeyConstraint('kimai2_activities', ['activity_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_4A7F11BE81C06096'); $activityRates->addUniqueIndex(['user_id', 'activity_id'], 'UNIQ_4A7F11BEA76ED39581C06096'); - $activityRates->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($activityRates, ['id']); } public function down(Schema $schema): void diff --git a/migrations/Version20200308171950.php b/migrations/Version20200308171950.php index 2078f3d6f..71abed8a8 100644 --- a/migrations/Version20200308171950.php +++ b/migrations/Version20200308171950.php @@ -45,7 +45,7 @@ final class Version20200308171950 extends AbstractMigration $invoices->addUniqueIndex(['invoice_filename'], 'UNIQ_76C38E372323B33D'); $invoices->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_76C38E37A76ED395'); $invoices->addForeignKeyConstraint('kimai2_customers', ['customer_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_76C38E379395C3F3'); - $invoices->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($invoices, ['id']); } public function down(Schema $schema): void diff --git a/migrations/Version20200524142042.php b/migrations/Version20200524142042.php index 8e49cc00a..fc0041dbf 100644 --- a/migrations/Version20200524142042.php +++ b/migrations/Version20200524142042.php @@ -31,7 +31,7 @@ final class Version20200524142042 extends AbstractMigration $sessions->addColumn('data', 'blob', ['length' => 65535, 'notnull' => true]); $sessions->addColumn('time', 'integer', ['unsigned' => true, 'notnull' => true]); $sessions->addColumn('lifetime', 'integer', ['unsigned' => true, 'notnull' => true]); - $sessions->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($sessions, ['id']); } public function down(Schema $schema): void diff --git a/migrations/Version20200725213424.php b/migrations/Version20200725213424.php index 5e54a9d82..158b32d18 100644 --- a/migrations/Version20200725213424.php +++ b/migrations/Version20200725213424.php @@ -33,7 +33,7 @@ final class Version20200725213424 extends AbstractMigration $activityTeams->addColumn('team_id', 'integer', ['length' => 11, 'notnull' => true]); $activityTeams->addForeignKeyConstraint('kimai2_activities', ['activity_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_986998DA81C06096'); $activityTeams->addForeignKeyConstraint('kimai2_teams', ['team_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_986998DA296CD8AE'); - $activityTeams->setPrimaryKey(['activity_id', 'team_id']); + $this->addPrimaryKeyConstraint($activityTeams, ['activity_id', 'team_id']); } public function down(Schema $schema): void diff --git a/migrations/Version20210316224358.php b/migrations/Version20210316224358.php index 4337288a2..f4c94d061 100644 --- a/migrations/Version20210316224358.php +++ b/migrations/Version20210316224358.php @@ -36,7 +36,7 @@ final class Version20210316224358 extends AbstractMigration $bookmarks->addColumn('content', 'text', ['notnull' => true]); $bookmarks->addForeignKeyConstraint('kimai2_users', ['user_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_4016EF25A76ED395'); $bookmarks->addUniqueIndex(['user_id', 'name'], 'UNIQ_4016EF25A76ED3955E237E06'); - $bookmarks->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($bookmarks, ['id']); } public function down(Schema $schema): void diff --git a/migrations/Version20210802174318.php b/migrations/Version20210802174318.php index c7331b8b4..2d4e2fe66 100644 --- a/migrations/Version20210802174318.php +++ b/migrations/Version20210802174318.php @@ -30,7 +30,7 @@ final class Version20210802174318 extends AbstractMigration $teamMember->addColumn('id', 'integer', ['autoincrement' => true, 'notnull' => true]); $teamMember->addColumn('teamlead', 'boolean', ['notnull' => true, 'default' => false]); $teamMember->dropPrimaryKey(); - $teamMember->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($teamMember, ['id']); $teamMember->addUniqueIndex(['user_id', 'team_id'], 'UNIQ_B5E92CF8A76ED395296CD8AE'); } @@ -41,6 +41,6 @@ final class Version20210802174318 extends AbstractMigration $teamMember->dropPrimaryKey(); $teamMember->dropColumn('teamlead'); $teamMember->dropColumn('id'); - $teamMember->setPrimaryKey(['user_id', 'team_id']); + $this->addPrimaryKeyConstraint($teamMember, ['user_id', 'team_id']); } } diff --git a/migrations/Version20220101204501.php b/migrations/Version20220101204501.php index e96d0a690..6c7bb6cdf 100644 --- a/migrations/Version20220101204501.php +++ b/migrations/Version20220101204501.php @@ -29,7 +29,7 @@ final class Version20220101204501 extends AbstractMigration $table->addColumn('name', 'string', ['notnull' => true, 'length' => 50]); $table->addColumn('value', 'text', ['notnull' => false, 'length' => 65535]); $table->addColumn('visible', 'boolean', ['notnull' => true, 'default' => false]); - $table->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($table, ['id']); $table->addIndex(['invoice_id'], 'IDX_7EDC37D92989F1FD'); $table->addUniqueIndex(['invoice_id', 'name'], 'UNIQ_7EDC37D92989F1FD5E237E06'); $table->addForeignKeyConstraint('kimai2_invoices', ['invoice_id'], ['id'], ['onDelete' => 'CASCADE'], 'FK_7EDC37D92989F1FD'); diff --git a/migrations/Version20230327143628.php b/migrations/Version20230327143628.php index f4bbe284c..8eb7e0d00 100644 --- a/migrations/Version20230327143628.php +++ b/migrations/Version20230327143628.php @@ -35,7 +35,7 @@ final class Version20230327143628 extends AbstractMigration $workingTimes->addColumn('expected', 'integer', ['notnull' => true]); $workingTimes->addColumn('actual', 'integer', ['notnull' => true]); $workingTimes->addColumn('approved_at', 'datetime', ['notnull' => false, 'default' => null]); - $workingTimes->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($workingTimes, ['id']); $workingTimes->addIndex(['user_id'], 'IDX_F95E4933A76ED395'); $workingTimes->addIndex(['approved_by'], 'IDX_F95E49334EA3CB3D'); $workingTimes->addUniqueIndex(['user_id', 'date'], 'UNIQ_F95E4933A76ED395AA9E377A'); diff --git a/migrations/Version20240214061246.php b/migrations/Version20240214061246.php index 601bf7767..105d2a936 100644 --- a/migrations/Version20240214061246.php +++ b/migrations/Version20240214061246.php @@ -33,7 +33,7 @@ final class Version20240214061246 extends AbstractMigration $accessTokens->addColumn('last_usage', 'datetime_immutable', ['notnull' => false, 'default' => null]); $accessTokens->addColumn('expires_at', 'datetime_immutable', ['notnull' => false, 'default' => null]); - $accessTokens->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($accessTokens, ['id']); $accessTokens->addIndex(['user_id'], 'IDX_6FB0DB1EA76ED395'); $accessTokens->addUniqueIndex(['token'], 'UNIQ_6FB0DB1E5F37A13B'); diff --git a/migrations/Version20250608143244.php b/migrations/Version20250608143244.php index 4fa3d405c..2bfa11e1f 100644 --- a/migrations/Version20250608143244.php +++ b/migrations/Version20250608143244.php @@ -33,7 +33,7 @@ final class Version20250608143244 extends AbstractMigration $table->addColumn('columns', 'json', ['notnull' => true]); $table->addColumn('options', 'json', ['notnull' => true]); - $table->setPrimaryKey(['id']); + $this->addPrimaryKeyConstraint($table, ['id']); $table->addUniqueIndex(['title'], 'UNIQ_2F0CA26F2B36786B'); } diff --git a/migrations/Version20260101010000.php b/migrations/Version20260101010000.php new file mode 100644 index 000000000..e6776b3ea --- /dev/null +++ b/migrations/Version20260101010000.php @@ -0,0 +1,109 @@ +connection; + + $rows = $connection->fetchAllAssociative('SELECT id, roles FROM kimai2_users'); + + foreach ($rows as $row) { + $id = $row['id']; + $value = $row['roles']; + $data = []; + + if (\is_string($value) && str_starts_with($value, 'a:')) { + $data = unserialize($value); + } + + if (!\is_array($data)) { + $data = []; + } + + $json = json_encode($data); + + $connection->executeStatement('UPDATE kimai2_users SET roles = :data WHERE id = :id', [ + 'data' => $json, + 'id' => $id, + ]); + } + + $table = $schema->getTable('kimai2_users'); + $table->dropColumn('api_token'); + + $column = $table->getColumn('roles'); + $column->setType(Type::getType(Types::JSON)); + $column->setComment('(DC2Type:json)'); + $column->setNotnull(true); + + $table = $schema->getTable('kimai2_timesheet'); + $table->dropColumn('category'); + + $this->addSql("DELETE FROM kimai2_user_preferences WHERE `name` = 'export_decimal'"); + } + + public function down(Schema $schema): void + { + $connection = $this->connection; + + // this will leave behind a json_valid() check in mariadb + $connection->executeStatement('ALTER TABLE kimai2_users CHANGE roles roles LONGTEXT NOT NULL COMMENT \'(DC2Type:array)\''); + + // Fetch the existing rows from the table + $rows = $connection->fetchAllAssociative('SELECT id, roles FROM kimai2_users'); + + // Iterate over each row + foreach ($rows as $row) { + $id = $row['id']; + $roles = $row['roles']; + $data = []; + + if (json_validate($roles)) { + $data = json_decode($roles, true); + } + + if (!\is_array($data)) { + $data = []; + } + + $connection->executeStatement('UPDATE kimai2_users SET roles = :roles WHERE id = :id', [ + 'roles' => serialize($data), + 'id' => $id, + ]); + } + + $timesheetTable = $schema->getTable('kimai2_timesheet'); + $timesheetTable->addColumn('category', 'string', ['length' => 10, 'notnull' => true, 'default' => 'work']); + + $usersTable = $schema->getTable('kimai2_users'); + $usersTable->addColumn('api_token', 'string', ['length' => 255, 'notnull' => false, 'default' => null]); + } + + public function isTransactional(): bool + { + return false; + } +} diff --git a/package.json b/package.json index ea14027df..32cb20fc5 100644 --- a/package.json +++ b/package.json @@ -1,58 +1,60 @@ { - "name": "kimai", - "homepage": "https://github.com/kimai/kimai", - "license": "AGPL", - "maintainers": [ - { - "name": "Kevin Papst", - "url": "https://www.kevinpapst.de" - } - ], - "repository": { - "type": "git", - "url": "git+https://github.com/kimai/kimai.git" - }, - "scripts": { - "dev-server": "yarn encore dev-server", - "dev": "yarn encore dev", - "watch": "yarn encore dev --watch", - "lint": "yarn eslint assets/js/", - "build": "yarn encore production" - }, - "browserslist": [ - "defaults" - ], - "dependencies": { - "@babel/core": "^7", - "@babel/eslint-parser": "^7", - "@babel/plugin-syntax-dynamic-import": "^7", - "@babel/preset-env": "^7", - "@eslint/js": "^9", - "@fortawesome/fontawesome-free": "^6", - "@fullcalendar/bootstrap5": "^5", - "@fullcalendar/core": "^5", - "@fullcalendar/daygrid": "^5", - "@fullcalendar/google-calendar": "^5", - "@fullcalendar/icalendar": "^5", - "@fullcalendar/interaction": "^5", - "@fullcalendar/timegrid": "^5", - "@popperjs/core": "^2", - "@symfony/webpack-encore": "^5", - "@tabler/core": "1.4", - "bootstrap": "^5.3", - "chart.js": "^4", - "core-js": "^3", - "eslint": "^9", - "globals": "^15", - "highlight.js": "^11.11.1", - "litepicker": "^2", - "luxon": "^3", - "sass": "^1", - "sass-loader": "^16", - "sortablejs": "^1.15.6", - "tom-select": "^2.4.3", - "webpack": "^5", - "webpack-cli": "^5" - }, - "packageManager": "yarn@4.5.3" + "name": "kimai", + "homepage": "https://github.com/kimai/kimai", + "license": "AGPL", + "private": true, + "maintainers": [ + { + "name": "Kevin Papst", + "url": "https://www.kevinpapst.de" + } + ], + "repository": { + "type": "git", + "url": "git+https://github.com/kimai/kimai.git" + }, + "scripts": { + "dev-server": "yarn encore dev-server", + "dev": "yarn encore dev", + "watch": "yarn encore dev --watch", + "lint": "yarn eslint assets/js/", + "build": "yarn encore production" + }, + "browserslist": [ + "defaults" + ], + "dependencies": { + "@babel/core": "^7", + "@babel/eslint-parser": "^7", + "@babel/plugin-syntax-dynamic-import": "^7", + "@babel/preset-env": "^7", + "@eslint/js": "^9", + "@fortawesome/fontawesome-free": "^6", + "@fullcalendar/bootstrap5": "^5", + "@fullcalendar/core": "^5", + "@fullcalendar/daygrid": "^5", + "@fullcalendar/google-calendar": "^5", + "@fullcalendar/icalendar": "^5", + "@fullcalendar/interaction": "^5", + "@fullcalendar/timegrid": "^5", + "@popperjs/core": "^2", + "@symfony/webpack-encore": "^5", + "@tabler/core": "1.4", + "bootstrap": "^5.3", + "chart.js": "^4", + "core-js": "^3", + "eslint": "^9", + "globals": "^15", + "gridstack": "^7", + "highlight.js": "^11", + "litepicker": "^2", + "luxon": "^3", + "sass": "^1", + "sass-loader": "^16", + "sortablejs": "^1.15", + "tom-select": "^2", + "webpack": "^5", + "webpack-cli": "^5" + }, + "packageManager": "yarn@4.5.3" } diff --git a/phpstan.neon b/phpstan.neon index e3451c7f3..fccfb9694 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -49,16 +49,6 @@ parameters: count: 1 path: src/API/ActivityController.php - - - message: "#^Method App\\\\API\\\\Authentication\\\\TokenAuthenticator\\:\\:getCredentials\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/API/Authentication/TokenAuthenticator.php - - - - message: "#^Parameter \\#2 \\$plainPassword of method Symfony\\\\Component\\\\PasswordHasher\\\\PasswordHasherInterface\\:\\:verify\\(\\) expects string, string\\|null given\\.$#" - count: 1 - path: src/API/Authentication/TokenAuthenticator.php - - message: "#^Parameter \\#1 \\$name of method App\\\\Entity\\\\Customer\\:\\:getMetaField\\(\\) expects string, mixed given\\.$#" count: 1 @@ -179,11 +169,6 @@ parameters: count: 1 path: src/Command/AbstractUserCommand.php - - - message: "#^Parameter \\#1 \\$string of function trim expects string, string\\|null given\\.$#" - count: 1 - path: src/Command/AbstractUserCommand.php - - message: "#^Parameter \\#1 \\$username of method App\\\\User\\\\UserService\\:\\:findUserByUsernameOrThrowException\\(\\) expects string, mixed given\\.$#" count: 1 @@ -404,11 +389,6 @@ parameters: count: 1 path: src/Command/PromoteUserCommand.php - - - message: "#^Parameter \\#3 \\$length of function substr expects int\\|null, int\\<0, max\\>\\|false given\\.$#" - count: 1 - path: src/Command/RegenerateLocalesCommand.php - - message: "#^Cannot call method find\\(\\) on Symfony\\\\Component\\\\Console\\\\Application\\|null\\.$#" count: 4 @@ -594,21 +574,6 @@ parameters: count: 1 path: src/Configuration/SystemConfiguration.php - - - message: "#^Method App\\\\Configuration\\\\SystemConfiguration\\:\\:offsetExists\\(\\) has parameter \\$offset with no type specified\\.$#" - count: 1 - path: src/Configuration/SystemConfiguration.php - - - - message: "#^Method App\\\\Configuration\\\\SystemConfiguration\\:\\:offsetGet\\(\\) has parameter \\$offset with no type specified\\.$#" - count: 1 - path: src/Configuration/SystemConfiguration.php - - - - message: "#^Parameter \\#1 \\$key of method App\\\\Configuration\\\\SystemConfiguration\\:\\:set\\(\\) expects string, mixed given\\.$#" - count: 1 - path: src/Configuration/SystemConfiguration.php - - message: "#^Parameter \\#1 \\$string of function trim expects string, bool\\|float\\|int\\|string given\\.$#" count: 1 @@ -1164,21 +1129,11 @@ parameters: count: 1 path: src/Entity/Team.php - - - message: "#^Method App\\\\Entity\\\\Timesheet\\:\\:getCategory\\(\\) should return string but returns string\\|null\\.$#" - count: 1 - path: src/Entity/Timesheet.php - - message: "#^Method App\\\\Entity\\\\Timesheet\\:\\:getMetaFields\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#" count: 1 path: src/Entity/Timesheet.php - - - message: "#^Method App\\\\Entity\\\\Timesheet\\:\\:getTags\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#" - count: 1 - path: src/Entity/Timesheet.php - - message: "#^Parameter \\#1 \\$name of method App\\\\Entity\\\\Timesheet\\:\\:getMetaField\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -1254,21 +1209,6 @@ parameters: count: 1 path: src/Entity/User.php - - - message: "#^Method App\\\\Entity\\\\User\\:\\:setConfirmationToken\\(\\) has parameter \\$confirmationToken with no type specified\\.$#" - count: 1 - path: src/Entity/User.php - - - - message: "#^Method App\\\\Entity\\\\User\\:\\:setPassword\\(\\) has parameter \\$password with no type specified\\.$#" - count: 1 - path: src/Entity/User.php - - - - message: "#^Method App\\\\Entity\\\\User\\:\\:setPlainPassword\\(\\) has parameter \\$password with no type specified\\.$#" - count: 1 - path: src/Entity/User.php - - message: "#^Method App\\\\Entity\\\\User\\:\\:setRoles\\(\\) has parameter \\$roles with no value type specified in iterable type array\\.$#" count: 1 @@ -1354,11 +1294,6 @@ parameters: count: 1 path: src/Event/RevenueStatisticEvent.php - - - message: "#^Method App\\\\Event\\\\ThemeJavascriptTranslationsEvent\\:\\:getTranslations\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Event/ThemeJavascriptTranslationsEvent.php - - message: "#^Parameter \\#1 \\$string of function strtolower expects string, string\\|null given\\.$#" count: 2 @@ -1419,16 +1354,6 @@ parameters: count: 1 path: src/Export/Annotation/Order.php - - - message: "#^Method App\\\\Export\\\\Base\\\\HtmlRenderer\\:\\:getOptions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Export/Base/HtmlRenderer.php - - - - message: "#^Method App\\\\Export\\\\Base\\\\PDFRenderer\\:\\:getOptions\\(\\) return type has no value type specified in iterable type array\\.$#" - count: 1 - path: src/Export/Base/PDFRenderer.php - - message: "#^Method App\\\\Export\\\\Base\\\\PDFRenderer\\:\\:getPdfOptions\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -1929,61 +1854,6 @@ parameters: count: 1 path: src/Form/TimesheetPreCreateForm.php - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addActivitySelect\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addCustomerMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addCustomerSelect\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addDateRange\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addOrderBy\\(\\) has parameter \\$allowedColumns with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addProjectMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addProjectSelect\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addTeamsChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Method App\\\\Form\\\\Toolbar\\\\AbstractToolbarForm\\:\\:addUsersChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Form/Toolbar/AbstractToolbarForm.php - - - - message: "#^Parameter \\#1 \\$user of method App\\\\Repository\\\\Query\\\\BaseFormTypeQuery\\:\\:setUser\\(\\) expects App\\\\Entity\\\\User, mixed given\\.$#" - count: 2 - path: src/Form/Toolbar/AbstractToolbarForm.php - - message: "#^Method App\\\\Form\\\\Toolbar\\\\ActivityToolbarForm\\:\\:addActivityMultiChoice\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" count: 1 @@ -3321,7 +3191,7 @@ parameters: - message: "#^Parameter \\#1 \\$identifier of method App\\\\Entity\\\\User\\:\\:setUserIdentifier\\(\\) expects string, string\\|null given\\.$#" - count: 2 + count: 1 path: src/Saml/SamlProvider.php - @@ -3329,16 +3199,6 @@ parameters: count: 1 path: src/Saml/SamlProvider.php - - - message: "#^Property App\\\\Saml\\\\Security\\\\SamlAuthenticationFailureHandler\\:\\:\\$defaultOptions has no type specified\\.$#" - count: 1 - path: src/Saml/Security/SamlAuthenticationFailureHandler.php - - - - message: "#^Property App\\\\Saml\\\\Security\\\\SamlAuthenticationSuccessHandler\\:\\:\\$defaultOptions has no type specified\\.$#" - count: 1 - path: src/Saml/Security/SamlAuthenticationSuccessHandler.php - - message: "#^Method App\\\\Security\\\\KimaiUserProvider\\:\\:getProviders\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -3539,21 +3399,6 @@ parameters: count: 1 path: src/Twig/LocaleFormatExtensions.php - - - message: "#^Method App\\\\Twig\\\\PaginationExtension\\:\\:createRouteGenerator\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Twig/PaginationExtension.php - - - - message: "#^Method App\\\\Twig\\\\PaginationExtension\\:\\:renderPagination\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#" - count: 1 - path: src/Twig/PaginationExtension.php - - - - message: "#^Method App\\\\Twig\\\\PaginationExtension\\:\\:renderPagination\\(\\) has parameter \\$pager with generic class Pagerfanta\\\\Pagerfanta but does not specify its types\\: T$#" - count: 1 - path: src/Twig/PaginationExtension.php - - message: "#^Method App\\\\Twig\\\\Runtime\\\\ThemeExtension\\:\\:actions\\(\\) has parameter \\$payload with no value type specified in iterable type array\\.$#" count: 1 @@ -3589,11 +3434,6 @@ parameters: count: 3 path: src/Utils/Color.php - - - message: "#^Class App\\\\Utils\\\\DataTable implements generic interface IteratorAggregate but does not specify its types\\: TKey, TValue$#" - count: 1 - path: src/Utils/DataTable.php - - message: "#^Method App\\\\Utils\\\\DataTable\\:\\:addColumn\\(\\) has parameter \\$column with no value type specified in iterable type array\\.$#" count: 1 @@ -3604,11 +3444,6 @@ parameters: count: 1 path: src/Utils/DataTable.php - - - message: "#^Method App\\\\Utils\\\\DataTable\\:\\:getIterator\\(\\) should return Traversable\\ but returns Traversable\\<\\(int\\|string\\), mixed\\>\\|null\\.$#" - count: 1 - path: src/Utils/DataTable.php - - message: "#^Method App\\\\Utils\\\\DataTable\\:\\:getOptions\\(\\) return type has no value type specified in iterable type array\\.$#" count: 1 @@ -3749,11 +3584,6 @@ parameters: count: 1 path: src/Utils/PageSetup.php - - - message: "#^Class App\\\\Utils\\\\Pagination extends generic class Pagerfanta\\\\Pagerfanta but does not specify its types\\: T$#" - count: 1 - path: src/Utils/Pagination.php - - message: "#^Parameter \\#1 \\$class of method App\\\\Utils\\\\PaginationTemplate\\:\\:linkLi\\(\\) expects string, mixed given\\.$#" count: 1 @@ -3859,16 +3689,6 @@ parameters: count: 1 path: src/Utils/ReleaseVersion.php - - - message: "#^Cannot access offset 'pattern' on mixed\\.$#" - count: 1 - path: src/Validator/Constraints/Duration.php - - - - message: "#^Parameter \\#1 \\$pattern of method Symfony\\\\Component\\\\Validator\\\\Constraints\\\\Regex\\:\\:__construct\\(\\) expects array\\|string\\|null, mixed given\\.$#" - count: 1 - path: src/Validator/Constraints/Duration.php - - message: "#^Parameter \\#1 \\$value \\(App\\\\Entity\\\\Team\\) of method App\\\\Validator\\\\Constraints\\\\TeamValidator\\:\\:validate\\(\\) should be contravariant with parameter \\$value \\(mixed\\) of method Symfony\\\\Component\\\\Validator\\\\ConstraintValidatorInterface\\:\\:validate\\(\\)$#" count: 2 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 577d748af..d807db45d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,8 +1,12 @@ + + - - - - - - - - - - - - - - - - + + + - - - - - tests/ - - - - - - - - src/ - templates/ - - - migrations/ - assets/ - bin/ - config/ - node_modules/ - public/ - tests/ - translations/ - var/ - vendor/ - - + CREATE DATABASE IF NOT EXISTS `kimai2_test`; + CREATE USER IF NOT EXISTS `kimai2_test`@127.0.0.1; + ALTER USER `kimai2_test`@127.0.0.1 IDENTIFIED BY "kimai2_test"; + GRANT execute,select,insert,update,delete,create,alter,drop,index,references ON `kimai2_test`.* TO kimai2_test@127.0.0.1; + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + tests/ + + + + + + + + + + + + src/ + templates/ + + + migrations/ + assets/ + bin/ + config/ + node_modules/ + public/ + tests/ + translations/ + var/ + vendor/ + + diff --git a/public/browserconfig.xml b/public/browserconfig.xml index b8c7e3716..f1b794e3f 100644 --- a/public/browserconfig.xml +++ b/public/browserconfig.xml @@ -4,7 +4,7 @@ - #00a300 + #ffffff \ No newline at end of file diff --git a/public/build/app.5f84f245.js b/public/build/app.5f84f245.js new file mode 100644 index 000000000..f1f433633 --- /dev/null +++ b/public/build/app.5f84f245.js @@ -0,0 +1,2 @@ +/*! For license information please see app.5f84f245.js.LICENSE.txt */ +(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[524],{33:function(t,e,n){"use strict";var i=n(8097);class o{constructor(t){this._translations=t}get(t){return this._translations[t]}has(t){return t in this._translations}}class r{constructor(t){this._configurations=t}get(t){return this._configurations[t]}has(t){return t in this._configurations}isRTL(){return"rtl"===this.get("direction")}getLanguage(){return this.get("locale").replace("_","-")}is24Hours(){return!!this.get("twentyFourHours")}getFirstDayOfWeek(t=!0){void 0===t&&(t=!0);let e=this.get("first_dow_iso");return t||(e%=7),e}}class s{init(){}getId(){return null}setContainer(t){if(!(t instanceof a))throw new Error("Plugin was given an invalid KimaiContainer");this._core=t}getContainer(){return this._core}getConfiguration(t){return this.getContainer().getConfiguration().get(t)}getConfigurations(){return this.getContainer().getConfiguration()}getDateUtils(){return this.getPlugin("date")}getPlugin(t){return this.getContainer().getPlugin(t)}getTranslation(){return this.getContainer().getTranslation()}translate(t){return this.getTranslation().get(t)}escape(t){return this.getPlugin("escape").escapeForHtml(t)}trigger(t,e=null){this.getPlugin("event").trigger(t,e)}fetch(t,e={}){return this.getPlugin("fetch").fetch(t,e)}fetchForm(t,e={},n=null){n=n||t.getAttribute("action");const i=t.getAttribute("method").toUpperCase();if("GET"===i){const i=this.getPlugin("form").convertFormDataToQueryString(t,{},!0);n=n+(n.includes("?")?"&":"?")+i,e={method:"GET",...e}}else"POST"===i&&(e={method:"POST",body:new FormData(t),...e});return this.fetch(n,e)}isMobile(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)<576}}class a{constructor(t,e){if(!(t instanceof r))throw new Error("Configuration needs to a KimaiConfiguration instance");if(this._configuration=t,!(e instanceof o))throw new Error("Configuration needs to a KimaiTranslation instance");this._translation=e,this._plugins=[]}registerPlugin(t){if(!(t instanceof s))throw new Error("Invalid plugin given, needs to be a KimaiPlugin instance");return t.setContainer(this),this._plugins.push(t),t}getPlugin(t){for(let e of this._plugins)if(null!==e.getId()&&e.getId()===t)return e;throw new Error("Unknown plugin: "+t)}getPlugins(){return this._plugins}getTranslation(){return this._translation}getConfiguration(){return this._configuration}getUser(){return this.getPlugin("user")}}class l extends s{constructor(t){super(),this.dataAttribute=t}getId(){return"datatable-column-visibility"}init(){let t=document.querySelector("["+this.dataAttribute+"]");if(null!==t){this._id=t.getAttribute(this.dataAttribute),this._modal=document.getElementById("modal_"+this._id),this._modal.addEventListener("show.bs.modal",(()=>{this._evaluateCheckboxes()})),this._modal.querySelector("button[data-type=save]").addEventListener("click",(()=>{this._saveVisibility()})),this._modal.querySelector("button[data-type=reset]").addEventListener("click",(t=>{this._resetVisibility(t.currentTarget)})),this._modal.querySelectorAll("input[name=datatable_profile]").forEach((t=>{t.addEventListener("change",(()=>{const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("data-href")).then((()=>{localStorage.setItem("kimai_profile",t.getAttribute("value")),document.location.reload()})).catch((()=>{e.setAttribute("action",t.getAttribute("data-href")),e.submit()}))}))}));for(let t of this._modal.querySelectorAll("form input[type=checkbox]"))t.addEventListener("change",(()=>{this._changeVisibility(t.getAttribute("name"),t.checked)}))}}_evaluateCheckboxes(){const t=this._modal.getElementsByTagName("form")[0],e=document.getElementsByClassName("datatable_"+this._id)[0];for(let n of e.getElementsByTagName("th")){const e=n.getAttribute("data-field");if(null===e)continue;const i=t.querySelector("input[name="+e+"]");null!==i&&(i.checked="none"!==window.getComputedStyle(n).display)}}_saveVisibility(){const t=this._modal.getElementsByTagName("form")[0];this.fetchForm(t).then((()=>{document.location.reload()})).catch((()=>{t.submit()}))}_resetVisibility(t){const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("formaction")).then((()=>{document.location.reload()})).catch((()=>{e.setAttribute("action",t.getAttribute("formaction")),e.submit()}))}_changeVisibility(t,e){for(const n of document.getElementsByClassName("datatable_"+this._id)){let i=null;for(let o of n.getElementsByClassName("col_"+t)){if(null===i){let t="-none",n="d-table-cell";e||(t="-table-cell",n="d-none"),i="",o.classList.forEach((function(e,n,o){-1===e.indexOf(t)&&(i+=" "+e)})),-1===i.indexOf(n)&&(i+=" "+n)}o.className=i}}}}var c=n(9336);class u extends s{init(){[].slice.call(document.querySelectorAll('[data-toggle="tooltip"]')).map((function(t){return new c.m_(t)}));[...document.querySelectorAll(".offcanvas")].map((t=>new c.go(t)));this.getContainer().getPlugin("form").activateForm("div.page-wrapper form"),this._registerModalAutofocus("#remote_form_modal"),this.overlay=null,document.addEventListener("kimai.reloadContent",(t=>{if(null!==this.overlay)return;let e="body";void 0!==t.detail&&null!==t.detail&&(e=t.detail);const n=document.createElement("div");n.innerHTML='
',this.overlay=n.firstElementChild,document.querySelector(e).append(this.overlay)})),document.addEventListener("kimai.reloadedContent",(()=>{null!==this.overlay&&(this.overlay.remove(),this.overlay=null)}))}_registerModalAutofocus(t){if(this.isMobile())return;const e=document.querySelector(t);null!==e&&e.addEventListener("shown.bs.modal",(()=>{const t=e.querySelector("form");let n=t.querySelectorAll("[autofocus]");n.length<1&&(n=t.querySelectorAll("input[type=text],input[type=date],textarea,select")),n.length>0&&n[0].focus()}))}}var d=n(424);n(8214);class h extends s{supportsForm(t){return!1}activateForm(t){}destroyForm(t){}}class p extends h{constructor(t){super(),this._selector=t}init(){window.disableLitepickerStyles=!0,this._pickers=[]}supportsForm(t){return!0}activateForm(t){const e=this.getConfigurations().getFirstDayOfWeek(!1),n=this.getConfigurations().getLanguage();let i={buttonText:{previousMonth:'',nextMonth:'',apply:this.translate("confirm"),cancel:this.translate("cancel")}};const o=[].slice.call(t.querySelectorAll(this._selector)).map((t=>(void 0===t.dataset.format&&console.log("Trying to bind litepicker to an element without data-format attribute"),void 0!==t.hasAttribute("min")&&(i={...i,minDate:t.getAttribute("min")}),void 0!==t.hasAttribute("max")&&(i={...i,maxDate:t.getAttribute("max")}),i={...i,format:t.dataset.format,showTooltip:!1,element:t,lang:n,autoRefresh:!0,firstDay:e,setup:e=>{e.on("preselect",((t,n)=>{e._wasPreselected=!0})),e.on("selected",((n,i)=>{void 0!==e._wasPreselected&&(t.dispatchEvent(new Event("change",{bubbles:!0})),delete e._wasPreselected)})),void 0!==e.backdrop&&document.body.appendChild(e.backdrop)}},[t,new d.Litepicker(this.prepareOptions(i))])));this._pickers=this._pickers.concat(o)}prepareOptions(t){return{...t,plugins:["mobilefriendly"]}}destroyForm(t){[].slice.call(t.querySelectorAll(this._selector)).map((t=>{for(let e=0;e{this.reloadDatatable()};for(let t of e.split(" "))document.addEventListener(t,n);document.addEventListener("pagination-change",n),document.addEventListener("filter-change",n)}registerContextMenu(t){f.A.createForDataTable(t)}reloadDatatable(){const t=this.getContainer().getPlugin("toolbar").getSelector(),e=document.querySelector(t),n=t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector(this._contentArea);document.querySelector(this._contentArea).replaceWith(n),this.registerContextMenu(this._selector),document.dispatchEvent(new Event("kimai.reloadedContent"))};document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this._contentArea})),null!==e?this.fetchForm(e).then((t=>{t.text().then(n)})).catch((()=>{e.submit()})):this.fetch(document.location).then((t=>{t.text().then(n)})).catch((()=>{document.location.reload()}))}}class v extends s{constructor(t,e){super(),this._formSelector=t,this._actionClass=e}getId(){return"toolbar"}init(){const t=this.getSelector();this._registerPagination(t),this._registerSortableTables(t),this._registerAlternativeSubmitActions(t,this._actionClass),[].slice.call(document.querySelectorAll(t+" input")).map((e=>{e.addEventListener("change",(e=>{switch(e.target.id){case"order":case"orderBy":case"page":break;default:document.querySelector(t+" input#page").value=1}})),this.triggerChange()})),[].slice.call(document.querySelectorAll(t+" select")).map((e=>{e.addEventListener("change",(e=>{let n=!0;switch(e.target.id){case"customer":null!==document.querySelector(t+" select#project")&&(n=!1);break;case"project":null!==document.querySelector(t+" select#activity")&&(n=!1)}document.querySelector(t+" input#page").value=1,n&&this.triggerChange()}))}))}_registerAlternativeSubmitActions(t,e){document.addEventListener("click",(function(n){let i=n.target;for(;null!==i&&"function"==typeof i.matches&&!i.matches("body");){if(i.classList.contains(e)){const e=document.querySelector(t);if(null===e)return;const o=e.getAttribute("action"),r=e.getAttribute("method");void 0!==i.dataset.target&&(e.target=i.dataset.target),e.action=i.href,void 0!==i.dataset.method&&(e.method=i.dataset.method),e.submit(),e.target="",e.action=o,e.method=r,n.preventDefault(),n.stopPropagation()}i=i.parentNode}}))}_registerSortableTables(t){document.body.addEventListener("click",(e=>{if(!e.target.matches("th.sortable"))return;let n="DESC",i=e.target.dataset.order;e.target.classList.contains("sorting_desc")&&(n="ASC"),document.querySelector(t+" #orderBy").value=i,document.querySelector(t+" #order").value=n,document.querySelector(t+" #orderBy").dispatchEvent(new Event("change")),document.querySelector(t+" #order").dispatchEvent(new Event("change")),document.dispatchEvent(new Event("filter-change"))}))}_registerPagination(t){document.body.addEventListener("click",(e=>{if(!(e.target.matches("ul.pagination li a")||null!==e.target.parentNode&&e.target.parentNode.matches("ul.pagination li a")))return;let n=document.querySelector(t+" input#page");if(null===n)return;let i=e.target;i.matches("a")||(i=i.parentNode),e.preventDefault(),e.stopPropagation();let o=i.href.split("/"),r=o[o.length-1];return/\d/.test(r)||(r=1),n.value=r,n.dispatchEvent(new Event("change")),document.dispatchEvent(new Event("pagination-change")),!1}))}triggerChange(){document.dispatchEvent(new Event("toolbar-change"))}getSelector(){return this._formSelector}}class y extends s{getId(){return"api"}_headers(){const t=new Headers;return t.append("Content-Type","application/json"),t}get(t,e,n,i){if(void 0!==e){const n=new URLSearchParams(e).toString();""!==n&&(t=t+(t.includes("?")?"&":"?")+n)}void 0===i&&(i=t=>{this.handleError("An error occurred",t)}),this.fetch(t,{method:"GET",headers:this._headers()}).then((t=>{t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}post(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"POST",body:this._parseData(e),headers:this._headers()}).then((t=>{t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}patch(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"PATCH",body:this._parseData(e),headers:this._headers()}).then((t=>{204===t.statusCode?n():t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}delete(t,e,n){void 0===n&&(n=t=>{this.handleError("action.delete.error",t)}),this.fetch(t,{method:"DELETE",headers:this._headers()}).then((()=>{e()})).catch((t=>{n(t)}))}_parseData(t){return"object"==typeof t?JSON.stringify(t):t}handleError(t,e){if(void 0===e.headers)return;const n=e.headers.get("content-type");n&&-1!==n.indexOf("application/json")?e.json().then((n=>{let i=n.message;if(400===e.status&&n.errors){let t=[""+i+""];if(n.errors.errors)for(let e of n.errors.errors)t.push(e);if(n.errors.children)for(let e in n.errors.children){let i=n.errors.children[e];if(void 0!==i.errors&&i.errors.length>0)for(let e of i.errors)t.push(e)}t.length>0&&(i=t)}this.getPlugin("alert").error(t,i)})):e.text().then((()=>{const n="["+e.statusCode+"] "+e.statusText;this.getPlugin("alert").error(t,n)}))}}class b extends s{addClickHandler(t,e,n){document.body.addEventListener("click",(i=>{let o=i.target;for(;null!==o;){const e=o.tagName.toUpperCase();if("BODY"===e)return;if(o.matches(t))break;if("A"===e||"BUTTON"===e||"INPUT"===e||"LABEL"===e)return;for(let t of n)if(o.matches(t))return;o=o.parentNode}if(null===o)return;if(o.isContentEditable||o.parentNode.isContentEditable)return;if(!o.matches(t))return;for(let t of n)if(o.matches(t))return;i.preventDefault(),i.stopPropagation();let r=o.dataset.href;null==r&&(r=o.href),null!=r&&""!==r&&e(r)}))}}class _ extends b{constructor(t){super(),this._selector=t}init(){this.addClickHandler(this._selector,(function(t){window.location=t}),[])}}class w extends b{constructor(t,e){super(),this._selector=t,this._stopSelector=e}getId(){return"modal"}init(){this._isDirty=!1;const t=this._getModalElement();null!==t&&(t.addEventListener("hide.bs.modal",(e=>{if(this._isDirty){if(null===t.querySelector(".modal-body .remote_modal_is_dirty_warning")){const e=this.translate("modal.dirty"),n=document.createElement("div");n.innerHTML='

'+e+"

",t.querySelector(".modal-body").prepend(n.firstElementChild)}e.preventDefault()}else this._isDirty=!1,document.dispatchEvent(new Event("modal-hide"))})),t.addEventListener("hidden.bs.modal",(()=>{this.getContainer().getPlugin("form").destroyForm(this._getFormIdentifier()),t.querySelector(".modal-body").replaceWith("")})),t.addEventListener("show.bs.modal",(()=>{document.dispatchEvent(new Event("modal-show"))})),this.addClickHandler(this._selector,(t=>{this.openUrlInModal(t)}),this._stopSelector))}_getModal(){return c.aF.getOrCreateInstance(this._getModalElement())}openUrlInModal(t,e){const n=new Headers;n.append("X-Requested-With","Kimai-Modal"),this.fetch(t,{method:"GET",redirect:"follow",headers:n}).then((e=>{if(e.ok)return e.text().then((t=>{this._openFormInModal(t)}));window.location=t})).catch((n=>{null==e?window.location=t:e(n)}))}_getFormIdentifier(){return"#remote_form_modal .modal-content form"}_getModalElement(){return document.getElementById("remote_form_modal")}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}_openFormInModal(t){const e=this._getFormIdentifier();let n=this._getModalElement();const i=document.createElement("div");i.innerHTML=t;const o=this._makeScriptExecutable(i.querySelector("#form_modal .modal-content"));if(null!==o){let t=n.querySelector(".modal-dialog"),r=i.querySelector(".modal-dialog").classList.contains("modal-lg");r&&!t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),!r&&t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),n.querySelector(".modal-content").replaceWith(o),[].slice.call(n.querySelectorAll('[data-bs-dismiss="modal"]')).map((t=>{t.addEventListener("click",(()=>{this._isDirty=!1,this._getModal().hide()}))})),this.getContainer().getPlugin("form").activateForm(e)}let r=i.querySelector("div.alert");null!==r&&n.querySelector(".modal-body").prepend(r);const s=document.querySelector(e);s.addEventListener("change",(()=>{this._isDirty=!0})),s.addEventListener("submit",this._getEventHandler()),this._getModal().show()}_getEventHandler(){return void 0===this.eventHandler&&(this.eventHandler=t=>{const e=t.target;if(void 0!==e.target&&""!==e.target)return!0;const n=document.querySelector(this._getFormIdentifier()+" button[type=submit]");n.textContent=n.textContent+" …",n.disabled=!0;const i=e.dataset.formEvent,o=this.getContainer().getPlugin("event"),r=this.getContainer().getPlugin("alert");t.preventDefault(),t.stopPropagation();const s=new Headers;s.append("X-Requested-With","Kimai-Modal");const a={headers:s};this.fetchForm(e,a).then((t=>{t.text().then((t=>{const s=document.createElement("div");s.innerHTML=t;let a=!1,l=!1,c=!1;n.textContent=n.textContent.replace(" …",""),n.disabled=!1;const u=s.querySelector("#form_modal .modal-content");if(null!==u&&(a=null!==u.querySelector(".is-invalid"),a||(a=null!==u.querySelector(".invalid-feedback")),l=null!==u.querySelector("ul.list-unstyled li.text-danger"),c=null!==s.querySelector("div.alert-danger")),a||l||c)this._openFormInModal(t);else{o.trigger(i);let t=e.dataset.msgSuccess;null!=t&&""!==t||(t="action.update.success"),this._isDirty=!1,this._getModal().hide(),r.success(t)}}))})).catch((t=>{let i=e.dataset.msgError;null!=i&&""!==i||(i="action.update.error"),r.error(i,t.message),setTimeout((()=>{n.textContent=n.textContent.replace(" …",""),n.disabled=!1}),1500)}))}),this.eventHandler}}class k extends s{constructor(){super(),this._selector=".ticktac-menu",this._selectorEmpty=".ticktac-menu-empty",this._favIconUrl=null}getId(){return"active-records"}init(){if(null===document.querySelector(this._selector))return;const t=()=>{this.reloadActiveRecords()};document.addEventListener("kimai.timesheetUpdate",t),document.addEventListener("kimai.timesheetDelete",t),document.addEventListener("kimai.activityUpdate",t),document.addEventListener("kimai.activityDelete",t),document.addEventListener("kimai.projectUpdate",t),document.addEventListener("kimai.projectDelete",t),document.addEventListener("kimai.customerUpdate",t),document.addEventListener("kimai.customerDelete",t),this._updateBrowserTitle=!!this.getConfiguration("updateBrowserTitle");const e=()=>{this._updateDuration()};this._updatesHandler=setInterval(e,1e4),document.addEventListener("kimai.timesheetUpdate",e),document.addEventListener("kimai.reloadedContent",e)}_updateDuration(){const t=document.querySelectorAll('[data-since]:not([data-since=""])');if(this._updateBrowserTitle&&this._changeFavicon(t.length>0),0===t.length)return void(this._updateBrowserTitle&&(void 0===document.body.dataset.title?this._updateBrowserTitle=!1:document.title=document.body.dataset.title));const e=this.getDateUtils();let n=[];for(const i of t){const t=e.formatDuration(i.dataset.since);void 0!==i.dataset.replacer&&null!==i.dataset.title&&"?"!==t&&n.push(t),i.textContent=t}0!==n.length&&this._updateBrowserTitle&&(document.title=n.shift())}_setEntries(t){const e=t.length>0;for(let t of document.querySelectorAll(this._selectorEmpty))t.style.display=e?"none":"inline-block";for(let n of document.querySelectorAll(this._selector)){if(n.style.display=e?"inline-block":"none",!e)for(let t of n.querySelectorAll("[data-since]"))t.dataset.since="";const i=n.querySelector(".ticktac-stop");e?(i&&(i.accesskey="s"),this._replaceInNode(n,t[0])):i&&(i.accesskey=null)}this._updateDuration()}_replaceInNode(t,e){const n=this.getDateUtils(),i=t.querySelectorAll("[data-replacer]");for(let o of i){const i=o.dataset.replacer;"url"===i?o.dataset.href=t.dataset.href.replace("000",e.id):"activity"===i?o.innerText=e.activity.name:"project"===i?o.innerText=e.project.name:"customer"===i?o.innerText=e.project.customer.name:"duration"===i&&(o.dataset.since=e.begin,o.innerText=n.formatDuration(e.duration))}}reloadActiveRecords(){const t=this.getContainer().getPlugin("api"),e=document.querySelector(this._selector).dataset.api;t.get(e,{},(t=>{this._setEntries(t)}))}_changeFavicon(t){const e=document.createElement("canvas"),n=document.getElementById("favicon");null===this._favIconUrl&&(this._favIconUrl=n.href);const i=n.cloneNode(!0);if(e.getContext&&i){const o=window.devicePixelRatio,r=document.createElement("img");e.height=e.width=16*o,r.onload=function(){const r=e.getContext("2d");if(r.drawImage(this,0,0,e.width,e.height),t){const t=5.5*o;r.fillStyle="rgb(182,57,57)",r.fillRect(e.width/2-t/2,e.height/2-t/2,t,t)}i.href=e.toDataURL("image/png"),n.remove(),document.head.appendChild(i)},r.src=this._favIconUrl}}}class E extends s{getId(){return"event"}trigger(t,e=null){if(""!==t)for(const n of t.split(" ")){let t=new Event(n);null!==e&&(t=new CustomEvent(n,{detail:e})),document.dispatchEvent(t)}}}class D extends s{constructor(t){super(),this._selector=t}init(){document.addEventListener("click",(t=>{let e=t.target;for(;null!==e&&"function"==typeof e.matches&&!e.matches("body");){if(e.classList.contains(this._selector)){const n=e.dataset;let i=n.href;i||(i=e.getAttribute("href")),void 0!==n.question?this.getContainer().getPlugin("alert").question(n.question,(t=>{t&&this._callApi(i,n)})):this._callApi(i,n),t.preventDefault(),t.stopPropagation()}e=e.parentNode}}))}_callApi(t,e){const n=e.method,i=e.event,o=this.getContainer().getPlugin("api"),r=this.getContainer().getPlugin("event"),s=this.getContainer().getPlugin("alert"),a=()=>{r.trigger(i),void 0!==e.msgSuccess&&s.success(e.msgSuccess)},l=t=>{let n="action.update.error";void 0!==e.msgError&&(n=e.msgError),o.handleError(n,t)};let c={};if(void 0!==e.payload&&(c=e.payload),"PATCH"===n)o.patch(t,c,a,l);else if("POST"===n){let e={};o.post(t,e,a,l)}else"DELETE"===n?o.delete(t,a,l):"GET"===n&&o.get(t,c,a,l)}}class T extends s{getId(){return"alert"}error(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t)),t=t.replace("%reason%",""),void 0===e&&(e=null),null!==e&&(n.has(e)&&(e=n.get(e)),Array.isArray(e)&&(e=e.join("
")));const i="alert_global_error",o=document.getElementById(i);null!==o&&c.aF.getOrCreateInstance(o).hide();const r='\n \n ";this._showModal(r)}warning(t){this._show("warning",t)}success(t){this._toast("success",t)}info(t){this._show("info",t)}_showModal(t){const e=document.body,n=document.createElement("template");n.innerHTML=t.trim();const i=n.content.firstChild;e.appendChild(i);const o=new c.aF(i);i.addEventListener("hidden.bs.modal",(function(){e.removeChild(i)})),o.show()}_show(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));const i='\n \n ";this._showModal(i)}_mapClass(t){return"info"===t||"success"===t||"warning"===t||"danger"===t?t:"error"===t?"danger":"primary"}_toast(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));let i='';"success"===t?i='':"warning"===t?i='':"danger"!==t&&"error"!==t||(i='');const o='',r=document.getElementById("toast-container"),s=document.createElement("template");s.innerHTML=o.trim();const a=s.content.firstChild;r.appendChild(a);const l=new c.y8(a);a.addEventListener("hidden.bs.toast",(function(){r.removeChild(a)})),l.show()}question(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t));const i=this._mapClass("info"),o='\n \n ",r=document.body,s=document.createElement("template");s.innerHTML=o.trim();const a=s.content.firstChild;r.appendChild(a),a.querySelector(".question-confirm").addEventListener("click",(()=>{e(!0)})),a.querySelector(".question-cancel").addEventListener("click",(()=>{e(!1)}));const l=new c.aF(a);a.addEventListener("hidden.bs.modal",(()=>{r.removeChild(a)})),l.show()}}function S(t,e){t.split(/\s+/).forEach((t=>{e(t)}))}class x{constructor(){this._events={}}on(t,e){S(t,(t=>{const n=this._events[t]||[];n.push(e),this._events[t]=n}))}off(t,e){var n=arguments.length;0!==n?S(t,(t=>{if(1===n)return void delete this._events[t];const i=this._events[t];void 0!==i&&(i.splice(i.indexOf(e),1),this._events[t]=i)})):this._events={}}trigger(t,...e){var n=this;S(t,(t=>{const i=n._events[t];void 0!==i&&i.forEach((t=>{t.apply(n,e)}))}))}}const O=t=>(t=t.filter(Boolean)).length<2?t[0]||"":1==I(t)?"["+t.join("")+"]":"(?:"+t.join("|")+")",C=t=>{if(!M(t))return t.join("");let e="",n=0;const i=()=>{n>1&&(e+="{"+n+"}")};return t.forEach(((o,r)=>{o!==t[r-1]?(i(),e+=o,n=1):n++})),i(),e},L=t=>{let e=Array.from(t);return O(e)},M=t=>new Set(t).size!==t.length,A=t=>(t+"").replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu,"\\$1"),I=t=>t.reduce(((t,e)=>Math.max(t,N(e))),0),N=t=>Array.from(t).length,P=t=>{if(1===t.length)return[[t]];let e=[];const n=t.substring(1);return P(n).forEach((function(n){let i=n.slice(0);i[0]=t.charAt(0)+i[0],e.push(i),i=n.slice(0),i.unshift(t.charAt(0)),e.push(i)})),e},F=[[0,65535]];let j,q;const H={},V={"/":"⁄∕",0:"߀",a:"ⱥɐɑ",aa:"ꜳ",ae:"æǽǣ",ao:"ꜵ",au:"ꜷ",av:"ꜹꜻ",ay:"ꜽ",b:"ƀɓƃ",c:"ꜿƈȼↄ",d:"đɗɖᴅƌꮷԁɦ",e:"ɛǝᴇɇ",f:"ꝼƒ",g:"ǥɠꞡᵹꝿɢ",h:"ħⱨⱶɥ",i:"ɨı",j:"ɉȷ",k:"ƙⱪꝁꝃꝅꞣ",l:"łƚɫⱡꝉꝇꞁɭ",m:"ɱɯϻ",n:"ꞥƞɲꞑᴎлԉ",o:"øǿɔɵꝋꝍᴑ",oe:"œ",oi:"ƣ",oo:"ꝏ",ou:"ȣ",p:"ƥᵽꝑꝓꝕρ",q:"ꝗꝙɋ",r:"ɍɽꝛꞧꞃ",s:"ßȿꞩꞅʂ",t:"ŧƭʈⱦꞇ",th:"þ",tz:"ꜩ",u:"ʉ",v:"ʋꝟʌ",vy:"ꝡ",w:"ⱳ",y:"ƴɏỿ",z:"ƶȥɀⱬꝣ",hv:"ƕ"};for(let t in V){let e=V[t]||"";for(let n=0;nt.normalize(e),$=t=>Array.from(t).reduce(((t,e)=>t+W(e)),""),W=t=>(t=B(t).toLowerCase().replace(R,(t=>H[t]||"")),B(t,"NFC"));const Y=t=>{const e={},n=(t,n)=>{const i=e[t]||new Set,o=new RegExp("^"+L(i)+"$","iu");n.match(o)||(i.add(A(n)),e[t]=i)};for(let e of function*(t){for(const[e,n]of t)for(let t=e;t<=n;t++){let e=String.fromCharCode(t),n=$(e);n!=e.toLowerCase()&&(n.length>3||0!=n.length&&(yield{folded:n,composed:e,code_point:t}))}}(t))n(e.folded,e.folded),n(e.folded,e.composed);return e},z=t=>{const e=Y(t),n={};let i=[];for(let t in e){let o=e[t];o&&(n[t]=L(o)),t.length>1&&i.push(A(t))}i.sort(((t,e)=>e.length-t.length));const o=O(i);return q=new RegExp("^"+o,"u"),n},U=(t,e=1)=>(e=Math.max(e,t.length-1),O(P(t).map((t=>((t,e=1)=>{let n=0;return t=t.map((t=>(j[t]&&(n+=t.length),j[t]||t))),n>=e?C(t):""})(t,e))))),Z=(t,e=!0)=>{let n=t.length>1?1:0;return O(t.map((t=>{let i=[];const o=e?t.length():t.length()-1;for(let e=0;e{for(const n of e){if(n.start!=t.start||n.end!=t.end)continue;if(n.substrs.join("")!==t.substrs.join(""))continue;let e=t.parts;const i=t=>{for(const n of e){if(n.start===t.start&&n.substr===t.substr)return!1;if(1!=t.length&&1!=n.length){if(t.startn.start)return!0;if(n.startt.start)return!0}}return!1};if(!(n.parts.filter(i).length>0))return!0}return!1};class K{parts;substrs;start;end;constructor(){this.parts=[],this.substrs=[],this.start=0,this.end=0}add(t){t&&(this.parts.push(t),this.substrs.push(t.substr),this.start=Math.min(t.start,this.start),this.end=Math.max(t.end,this.end))}last(){return this.parts[this.parts.length-1]}length(){return this.parts.length}clone(t,e){let n=new K,i=JSON.parse(JSON.stringify(this.parts)),o=i.pop();for(const t of i)n.add(t);let r=e.substr.substring(0,t-o.start),s=r.length;return n.add({start:o.start,end:o.start+s,length:s,substr:r}),n}}const J=t=>{var e;void 0===j&&(j=z(e||F)),t=$(t);let n="",i=[new K];for(let e=0;e0){a=a.sort(((t,e)=>t.length()-e.length()));for(let t of a)X(t,i)||i.push(t)}else if(e>0&&1==l.size&&!l.has("3")){n+=Z(i,!1);let t=new K;const e=i[0];e&&t.add(e.last()),i=[t]}}return n+=Z(i,!0),n},G=(t,e)=>{if(t)return t[e]},Q=(t,e)=>{if(t){for(var n,i=e.split(".");(n=i.shift())&&(t=t[n]););return t}},tt=(t,e,n)=>{var i,o;return t?(t+="",null==e.regex||-1===(o=t.search(e.regex))?0:(i=e.string.length/t.length,0===o&&(i+=.5),i*n)):0},et=(t,e)=>{var n=t[e];if("function"==typeof n)return n;n&&!Array.isArray(n)&&(t[e]=[n])},nt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},it=(t,e)=>"number"==typeof t&&"number"==typeof e?t>e?1:t(e=$(e+"").toLowerCase())?1:e>t?-1:0;class ot{items;settings;constructor(t,e){this.items=t,this.settings=e||{diacritics:!0}}tokenize(t,e,n){if(!t||!t.length)return[];const i=[],o=t.split(/\s+/);var r;return n&&(r=new RegExp("^("+Object.keys(n).map(A).join("|")+"):(.*)$")),o.forEach((t=>{let n,o=null,s=null;r&&(n=t.match(r))&&(o=n[1],t=n[2]),t.length>0&&(s=this.settings.diacritics?J(t)||null:A(t),s&&e&&(s="\\b"+s)),i.push({string:t,regex:s?new RegExp(s,"iu"):null,field:o})})),i}getScoreFunction(t,e){var n=this.prepareSearch(t,e);return this._getScoreFunction(n)}_getScoreFunction(t){const e=t.tokens,n=e.length;if(!n)return function(){return 0};const i=t.options.fields,o=t.weights,r=i.length,s=t.getAttrFn;if(!r)return function(){return 1};const a=1===r?function(t,e){const n=i[0].field;return tt(s(e,n),t,o[n]||1)}:function(t,e){var n=0;if(t.field){const i=s(e,t.field);!t.regex&&i?n+=1/r:n+=tt(i,t,1)}else nt(o,((i,o)=>{n+=tt(s(e,o),t,i)}));return n/r};return 1===n?function(t){return a(e[0],t)}:"and"===t.options.conjunction?function(t){var i,o=0;for(let n of e){if((i=a(n,t))<=0)return 0;o+=i}return o/n}:function(t){var i=0;return nt(e,(e=>{i+=a(e,t)})),i/n}}getSortFunction(t,e){var n=this.prepareSearch(t,e);return this._getSortFunction(n)}_getSortFunction(t){var e,n=[];const i=this,o=t.options,r=!t.query&&o.sort_empty?o.sort_empty:o.sort;if("function"==typeof r)return r.bind(this);const s=function(e,n){return"$score"===e?n.score:t.getAttrFn(i.items[n.id],e)};if(r)for(let e of r)(t.query||"$score"!==e.field)&&n.push(e);if(t.query){e=!0;for(let t of n)if("$score"===t.field){e=!1;break}e&&n.unshift({field:"$score",direction:"desc"})}else n=n.filter((t=>"$score"!==t.field));return n.length?function(t,e){var i,o;for(let r of n){if(o=r.field,i=("desc"===r.direction?-1:1)*it(s(o,t),s(o,e)))return i}return 0}:null}prepareSearch(t,e){const n={};var i=Object.assign({},e);if(et(i,"sort"),et(i,"sort_empty"),i.fields){et(i,"fields");const t=[];i.fields.forEach((e=>{"string"==typeof e&&(e={field:e,weight:1}),t.push(e),n[e.field]="weight"in e?e.weight:1})),i.fields=t}return{options:i,query:t.toLowerCase().trim(),tokens:this.tokenize(t,i.respect_word_boundaries,n),total:0,items:[],weights:n,getAttrFn:i.nesting?Q:G}}search(t,e){var n,i,o=this;i=this.prepareSearch(t,e),e=i.options,t=i.query;const r=e.score||o._getScoreFunction(i);t.length?nt(o.items,((t,o)=>{n=r(t),(!1===e.filter||n>0)&&i.items.push({score:n,id:o})})):nt(o.items,((t,e)=>{i.items.push({score:1,id:e})}));const s=o._getSortFunction(i);return s&&i.items.sort(s),i.total=i.items.length,"number"==typeof e.limit&&(i.items=i.items.slice(0,e.limit)),i}}const rt=t=>null==t?null:st(t),st=t=>"boolean"==typeof t?t?"1":"0":t+"",at=t=>(t+"").replace(/&/g,"&").replace(//g,">").replace(/"/g,"""),lt=(t,e)=>{var n;return function(i,o){var r=this;n&&(r.loading=Math.max(r.loading-1,0),clearTimeout(n)),n=setTimeout((function(){n=null,r.loadedSearches[i]=!0,t.call(r,i,o)}),e)}},ct=(t,e,n)=>{var i,o=t.trigger,r={};for(i of(t.trigger=function(){var n=arguments[0];if(-1===e.indexOf(n))return o.apply(t,arguments);r[n]=arguments},n.apply(t,[]),t.trigger=o,e))i in r&&o.apply(t,r[i])},ut=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},dt=(t,e,n,i)=>{t.addEventListener(e,n,i)},ht=(t,e)=>!!e&&(!!e[t]&&1===(e.altKey?1:0)+(e.ctrlKey?1:0)+(e.shiftKey?1:0)+(e.metaKey?1:0)),pt=(t,e)=>{const n=t.getAttribute("id");return n||(t.setAttribute("id",e),e)},mt=t=>t.replace(/[\\"']/g,"\\$&"),ft=(t,e)=>{e&&t.append(e)},gt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},vt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},yt=t=>"string"==typeof t&&t.indexOf("<")>-1,bt=(t,e)=>{var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!1),t.dispatchEvent(n)},_t=(t,e)=>{Object.assign(t.style,e)},wt=(t,...e)=>{var n=Et(e);(t=Dt(t)).map((t=>{n.map((e=>{t.classList.add(e)}))}))},kt=(t,...e)=>{var n=Et(e);(t=Dt(t)).map((t=>{n.map((e=>{t.classList.remove(e)}))}))},Et=t=>{var e=[];return gt(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Dt=t=>(Array.isArray(t)||(t=[t]),t),Tt=(t,e,n)=>{if(!n||n.contains(t))for(;t&&t.matches;){if(t.matches(e))return t;t=t.parentNode}},St=(t,e=0)=>e>0?t[t.length-1]:t[0],xt=(t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n},Ot=(t,e)=>{gt(e,((e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)}))},Ct=(t,e)=>{t.parentNode&&t.parentNode.replaceChild(e,t)},Lt=(t,e)=>{if(null===e)return;if("string"==typeof e){if(!e.length)return;e=new RegExp(e,"i")}const n=t=>3===t.nodeType?(t=>{var n=t.data.match(e);if(n&&t.data.length>0){var i=document.createElement("span");i.className="highlight";var o=t.splitText(n.index);o.splitText(n[0].length);var r=o.cloneNode(!0);return i.appendChild(r),Ct(o,i),1}return 0})(t):((t=>{1!==t.nodeType||!t.childNodes||/(script|style)/i.test(t.tagName)||"highlight"===t.className&&"SPAN"===t.tagName||Array.from(t.childNodes).forEach((t=>{n(t)}))})(t),0);n(t)},Mt="undefined"!=typeof navigator&&/Mac/.test(navigator.userAgent)?"metaKey":"ctrlKey";var At={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:null,createOnBlur:!1,createFilter:null,highlight:!0,openOnFocus:!0,shouldOpen:null,maxOptions:50,maxItems:null,hideSelected:null,duplicates:!1,addPrecedence:!1,selectOnTab:!1,preload:null,allowEmptyOption:!1,refreshThrottle:300,loadThrottle:300,loadingClass:"loading",dataAttr:null,optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"ts-wrapper",controlClass:"ts-control",dropdownClass:"ts-dropdown",dropdownContentClass:"ts-dropdown-content",itemClass:"item",optionClass:"option",dropdownParent:null,controlInput:'',copyClassesToDropdown:!1,placeholder:null,hidePlaceholder:null,shouldLoad:function(t){return t.length>0},render:{}};function It(t,e){var n=Object.assign({},At,e),i=n.dataAttr,o=n.labelField,r=n.valueField,s=n.disabledField,a=n.optgroupField,l=n.optgroupLabelField,c=n.optgroupValueField,u=t.tagName.toLowerCase(),d=t.getAttribute("placeholder")||t.getAttribute("data-placeholder");if(!d&&!n.allowEmptyOption){let e=t.querySelector('option[value=""]');e&&(d=e.textContent)}var h={placeholder:d,options:[],optgroups:[],items:[],maxItems:null};return"select"===u?(()=>{var e,u=h.options,d={},p=1;let m=0;var f=t=>{var e=Object.assign({},t.dataset),n=i&&e[i];return"string"==typeof n&&n.length&&(e=Object.assign(e,JSON.parse(n))),e},g=(t,e)=>{var i=rt(t.value);if(null!=i&&(i||n.allowEmptyOption)){if(d.hasOwnProperty(i)){if(e){var l=d[i][a];l?Array.isArray(l)?l.push(e):d[i][a]=[l,e]:d[i][a]=e}}else{var c=f(t);c[o]=c[o]||t.textContent,c[r]=c[r]||i,c[s]=c[s]||t.disabled,c[a]=c[a]||e,c.$option=t,c.$order=c.$order||++m,d[i]=c,u.push(c)}t.selected&&h.items.push(i)}};h.maxItems=t.hasAttribute("multiple")?null:1,gt(t.children,(t=>{var n,i,o;"optgroup"===(e=t.tagName.toLowerCase())?((o=f(n=t))[l]=o[l]||n.getAttribute("label")||"",o[c]=o[c]||p++,o[s]=o[s]||n.disabled,o.$order=o.$order||++m,h.optgroups.push(o),i=o[c],gt(n.children,(t=>{g(t,i)}))):"option"===e&&g(t)}))})():(()=>{const e=t.getAttribute(i);if(e)h.options=JSON.parse(e),gt(h.options,(t=>{h.items.push(t[r])}));else{var s=t.value.trim()||"";if(!n.allowEmptyOption&&!s.length)return;const e=s.split(n.delimiter);gt(e,(t=>{const e={};e[o]=t,e[r]=t,h.options.push(e)})),h.items=e}})(),Object.assign({},At,h,e)}var Nt=0;class Pt extends(function(t){return t.plugins={},class extends t{constructor(){super(...arguments),this.plugins={names:[],settings:{},requested:{},loaded:{}}}static define(e,n){t.plugins[e]={name:e,fn:n}}initializePlugins(t){var e,n;const i=this,o=[];if(Array.isArray(t))t.forEach((t=>{"string"==typeof t?o.push(t):(i.plugins.settings[t.name]=t.options,o.push(t.name))}));else if(t)for(e in t)t.hasOwnProperty(e)&&(i.plugins.settings[e]=t[e],o.push(e));for(;n=o.shift();)i.require(n)}loadPlugin(e){var n=this,i=n.plugins,o=t.plugins[e];if(!t.plugins.hasOwnProperty(e))throw new Error('Unable to find "'+e+'" plugin');i.requested[e]=!0,i.loaded[e]=o.fn.apply(n,[n.plugins.settings[e]||{}]),i.names.push(e)}require(t){var e=this,n=e.plugins;if(!e.plugins.loaded.hasOwnProperty(t)){if(n.requested[t])throw new Error('Plugin has circular dependency ("'+t+'")');e.loadPlugin(t)}return n.loaded[t]}}}(x)){constructor(t,e){var n;super(),this.order=0,this.isOpen=!1,this.isDisabled=!1,this.isReadOnly=!1,this.isInvalid=!1,this.isValid=!0,this.isLocked=!1,this.isFocused=!1,this.isInputHidden=!1,this.isSetup=!1,this.ignoreFocus=!1,this.ignoreHover=!1,this.hasOptions=!1,this.lastValue="",this.caretPos=0,this.loading=0,this.loadedSearches={},this.activeOption=null,this.activeItems=[],this.optgroups={},this.options={},this.userOptions={},this.items=[],this.refreshTimeout=null,Nt++;var i=vt(t);if(i.tomselect)throw new Error("Tom Select already initialized on this element");i.tomselect=this,n=(window.getComputedStyle&&window.getComputedStyle(i,null)).getPropertyValue("direction");const o=It(i,e);this.settings=o,this.input=i,this.tabIndex=i.tabIndex||0,this.is_select_tag="select"===i.tagName.toLowerCase(),this.rtl=/rtl/i.test(n),this.inputId=pt(i,"tomselect-"+Nt),this.isRequired=i.required,this.sifter=new ot(this.options,{diacritics:o.diacritics}),o.mode=o.mode||(1===o.maxItems?"single":"multi"),"boolean"!=typeof o.hideSelected&&(o.hideSelected="multi"===o.mode),"boolean"!=typeof o.hidePlaceholder&&(o.hidePlaceholder="multi"!==o.mode);var r=o.createFilter;"function"!=typeof r&&("string"==typeof r&&(r=new RegExp(r)),r instanceof RegExp?o.createFilter=t=>r.test(t):o.createFilter=t=>this.settings.duplicates||!this.options[t]),this.initializePlugins(o.plugins),this.setupCallbacks(),this.setupTemplates();const s=vt("
"),a=vt("
"),l=this._render("dropdown"),c=vt('
'),u=this.input.getAttribute("class")||"",d=o.mode;var h;if(wt(s,o.wrapperClass,u,d),wt(a,o.controlClass),ft(s,a),wt(l,o.dropdownClass,d),o.copyClassesToDropdown&&wt(l,u),wt(c,o.dropdownContentClass),ft(l,c),vt(o.dropdownParent||s).appendChild(l),yt(o.controlInput)){h=vt(o.controlInput);gt(["autocorrect","autocapitalize","autocomplete","spellcheck"],(t=>{i.getAttribute(t)&&Ot(h,{[t]:i.getAttribute(t)})})),h.tabIndex=-1,a.appendChild(h),this.focus_node=h}else o.controlInput?(h=vt(o.controlInput),this.focus_node=h):(h=vt(""),this.focus_node=a);this.wrapper=s,this.dropdown=l,this.dropdown_content=c,this.control=a,this.control_input=h,this.setup()}setup(){const t=this,e=t.settings,n=t.control_input,i=t.dropdown,o=t.dropdown_content,r=t.wrapper,s=t.control,a=t.input,l=t.focus_node,c={passive:!0},u=t.inputId+"-ts-dropdown";Ot(o,{id:u}),Ot(l,{role:"combobox","aria-haspopup":"listbox","aria-expanded":"false","aria-controls":u});const d=pt(l,t.inputId+"-ts-control"),h="label[for='"+(t=>t.replace(/['"\\]/g,"\\$&"))(t.inputId)+"']",p=document.querySelector(h),m=t.focus.bind(t);if(p){dt(p,"click",m),Ot(p,{for:d});const e=pt(p,t.inputId+"-ts-label");Ot(l,{"aria-labelledby":e}),Ot(o,{"aria-labelledby":e})}if(r.style.width=a.style.width,t.plugins.names.length){const e="plugin-"+t.plugins.names.join(" plugin-");wt([r,i],e)}(null===e.maxItems||e.maxItems>1)&&t.is_select_tag&&Ot(a,{multiple:"multiple"}),e.placeholder&&Ot(n,{placeholder:e.placeholder}),!e.splitOn&&e.delimiter&&(e.splitOn=new RegExp("\\s*"+A(e.delimiter)+"+\\s*")),e.load&&e.loadThrottle&&(e.load=lt(e.load,e.loadThrottle)),dt(i,"mousemove",(()=>{t.ignoreHover=!1})),dt(i,"mouseenter",(e=>{var n=Tt(e.target,"[data-selectable]",i);n&&t.onOptionHover(e,n)}),{capture:!0}),dt(i,"click",(e=>{const n=Tt(e.target,"[data-selectable]");n&&(t.onOptionSelect(e,n),ut(e,!0))})),dt(s,"click",(e=>{var i=Tt(e.target,"[data-ts-item]",s);i&&t.onItemSelect(e,i)?ut(e,!0):""==n.value&&(t.onClick(),ut(e,!0))})),dt(l,"keydown",(e=>t.onKeyDown(e))),dt(n,"keypress",(e=>t.onKeyPress(e))),dt(n,"input",(e=>t.onInput(e))),dt(l,"blur",(e=>t.onBlur(e))),dt(l,"focus",(e=>t.onFocus(e))),dt(n,"paste",(e=>t.onPaste(e)));const f=e=>{const o=e.composedPath()[0];if(!r.contains(o)&&!i.contains(o))return t.isFocused&&t.blur(),void t.inputState();o==n&&t.isOpen?e.stopPropagation():ut(e,!0)},g=()=>{t.isOpen&&t.positionDropdown()};dt(document,"mousedown",f),dt(window,"scroll",g,c),dt(window,"resize",g,c),this._destroy=()=>{document.removeEventListener("mousedown",f),window.removeEventListener("scroll",g),window.removeEventListener("resize",g),p&&p.removeEventListener("click",m)},this.revertSettings={innerHTML:a.innerHTML,tabIndex:a.tabIndex},a.tabIndex=-1,a.insertAdjacentElement("afterend",t.wrapper),t.sync(!1),e.items=[],delete e.optgroups,delete e.options,dt(a,"invalid",(()=>{t.isValid&&(t.isValid=!1,t.isInvalid=!0,t.refreshState())})),t.updateOriginalInput(),t.refreshItems(),t.close(!1),t.inputState(),t.isSetup=!0,a.disabled?t.disable():a.readOnly?t.setReadOnly(!0):t.enable(),t.on("change",this.onChange),wt(a,"tomselected","ts-hidden-accessible"),t.trigger("initialize"),!0===e.preload&&t.preload()}setupOptions(t=[],e=[]){this.addOptions(t),gt(e,(t=>{this.registerOptionGroup(t)}))}setupTemplates(){var t=this,e=t.settings.labelField,n=t.settings.optgroupLabelField,i={optgroup:t=>{let e=document.createElement("div");return e.className="optgroup",e.appendChild(t.options),e},optgroup_header:(t,e)=>'
'+e(t[n])+"
",option:(t,n)=>"
"+n(t[e])+"
",item:(t,n)=>"
"+n(t[e])+"
",option_create:(t,e)=>'
Add '+e(t.input)+"…
",no_results:()=>'
No results found
',loading:()=>'
',not_loading:()=>{},dropdown:()=>"
"};t.settings.render=Object.assign({},i,t.settings.render)}setupCallbacks(){var t,e,n={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",item_select:"onItemSelect",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(t in n)(e=this.settings[n[t]])&&this.on(t,e)}sync(t=!0){const e=this,n=t?It(e.input,{delimiter:e.settings.delimiter}):e.settings;e.setupOptions(n.options,n.optgroups),e.setValue(n.items||[],!0),e.lastQuery=null}onClick(){var t=this;if(t.activeItems.length>0)return t.clearActiveItems(),void t.focus();t.isFocused&&t.isOpen?t.blur():t.focus()}onMouseDown(){}onChange(){bt(this.input,"input"),bt(this.input,"change")}onPaste(t){var e=this;e.isInputHidden||e.isLocked?ut(t):e.settings.splitOn&&setTimeout((()=>{var t=e.inputValue();if(t.match(e.settings.splitOn)){var n=t.trim().split(e.settings.splitOn);gt(n,(t=>{rt(t)&&(this.options[t]?e.addItem(t):e.createItem(t))}))}}),0)}onKeyPress(t){var e=this;if(!e.isLocked){var n=String.fromCharCode(t.keyCode||t.which);return e.settings.create&&"multi"===e.settings.mode&&n===e.settings.delimiter?(e.createItem(),void ut(t)):void 0}ut(t)}onKeyDown(t){var e=this;if(e.ignoreHover=!0,e.isLocked)9!==t.keyCode&&ut(t);else{switch(t.keyCode){case 65:if(ht(Mt,t)&&""==e.control_input.value)return ut(t),void e.selectAll();break;case 27:return e.isOpen&&(ut(t,!0),e.close()),void e.clearActiveItems();case 40:if(!e.isOpen&&e.hasOptions)e.open();else if(e.activeOption){let t=e.getAdjacent(e.activeOption,1);t&&e.setActiveOption(t)}return void ut(t);case 38:if(e.activeOption){let t=e.getAdjacent(e.activeOption,-1);t&&e.setActiveOption(t)}return void ut(t);case 13:return void(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):(e.settings.create&&e.createItem()||document.activeElement==e.control_input&&e.isOpen)&&ut(t));case 37:return void e.advanceSelection(-1,t);case 39:return void e.advanceSelection(1,t);case 9:return void(e.settings.selectOnTab&&(e.canSelect(e.activeOption)&&(e.onOptionSelect(t,e.activeOption),ut(t)),e.settings.create&&e.createItem()&&ut(t)));case 8:case 46:return void e.deleteSelection(t)}e.isInputHidden&&!ht(Mt,t)&&ut(t)}}onInput(t){if(this.isLocked)return;const e=this.inputValue();this.lastValue!==e&&(this.lastValue=e,""!=e?(this.refreshTimeout&&window.clearTimeout(this.refreshTimeout),this.refreshTimeout=((t,e)=>e>0?window.setTimeout(t,e):(t.call(null),null))((()=>{this.refreshTimeout=null,this._onInput()}),this.settings.refreshThrottle)):this._onInput())}_onInput(){const t=this.lastValue;this.settings.shouldLoad.call(this,t)&&this.load(t),this.refreshOptions(),this.trigger("type",t)}onOptionHover(t,e){this.ignoreHover||this.setActiveOption(e,!1)}onFocus(t){var e=this,n=e.isFocused;if(e.isDisabled||e.isReadOnly)return e.blur(),void ut(t);e.ignoreFocus||(e.isFocused=!0,"focus"===e.settings.preload&&e.preload(),n||e.trigger("focus"),e.activeItems.length||(e.inputState(),e.refreshOptions(!!e.settings.openOnFocus)),e.refreshState())}onBlur(t){if(!1!==document.hasFocus()){var e=this;if(e.isFocused){e.isFocused=!1,e.ignoreFocus=!1;var n=()=>{e.close(),e.setActiveItem(),e.setCaret(e.items.length),e.trigger("blur")};e.settings.create&&e.settings.createOnBlur?e.createItem(null,n):n()}}}onOptionSelect(t,e){var n,i=this;e.parentElement&&e.parentElement.matches("[data-disabled]")||(e.classList.contains("create")?i.createItem(null,(()=>{i.settings.closeAfterSelect&&i.close()})):void 0!==(n=e.dataset.value)&&(i.lastQuery=null,i.addItem(n),i.settings.closeAfterSelect&&i.close(),!i.settings.hideSelected&&t.type&&/click/.test(t.type)&&i.setActiveOption(e)))}canSelect(t){return!!(this.isOpen&&t&&this.dropdown_content.contains(t))}onItemSelect(t,e){var n=this;return!n.isLocked&&"multi"===n.settings.mode&&(ut(t),n.setActiveItem(e,t),!0)}canLoad(t){return!!this.settings.load&&!this.loadedSearches.hasOwnProperty(t)}load(t){const e=this;if(!e.canLoad(t))return;wt(e.wrapper,e.settings.loadingClass),e.loading++;const n=e.loadCallback.bind(e);e.settings.load.call(e,t,n)}loadCallback(t,e){const n=this;n.loading=Math.max(n.loading-1,0),n.lastQuery=null,n.clearActiveOption(),n.setupOptions(t,e),n.refreshOptions(n.isFocused&&!n.isInputHidden),n.loading||kt(n.wrapper,n.settings.loadingClass),n.trigger("load",t,e)}preload(){var t=this.wrapper.classList;t.contains("preloaded")||(t.add("preloaded"),this.load(""))}setTextboxValue(t=""){var e=this.control_input;e.value!==t&&(e.value=t,bt(e,"update"),this.lastValue=t)}getValue(){return this.is_select_tag&&this.input.hasAttribute("multiple")?this.items:this.items.join(this.settings.delimiter)}setValue(t,e){ct(this,e?[]:["change"],(()=>{this.clear(e),this.addItems(t,e)}))}setMaxItems(t){0===t&&(t=null),this.settings.maxItems=t,this.refreshState()}setActiveItem(t,e){var n,i,o,r,s,a,l=this;if("single"!==l.settings.mode){if(!t)return l.clearActiveItems(),void(l.isFocused&&l.inputState());if("click"===(n=e&&e.type.toLowerCase())&&ht("shiftKey",e)&&l.activeItems.length){for(a=l.getLastActive(),(o=Array.prototype.indexOf.call(l.control.children,a))>(r=Array.prototype.indexOf.call(l.control.children,t))&&(s=o,o=r,r=s),i=o;i<=r;i++)t=l.control.children[i],-1===l.activeItems.indexOf(t)&&l.setActiveItemClass(t);ut(e)}else"click"===n&&ht(Mt,e)||"keydown"===n&&ht("shiftKey",e)?t.classList.contains("active")?l.removeActiveItem(t):l.setActiveItemClass(t):(l.clearActiveItems(),l.setActiveItemClass(t));l.inputState(),l.isFocused||l.focus()}}setActiveItemClass(t){const e=this,n=e.control.querySelector(".last-active");n&&kt(n,"last-active"),wt(t,"active last-active"),e.trigger("item_select",t),-1==e.activeItems.indexOf(t)&&e.activeItems.push(t)}removeActiveItem(t){var e=this.activeItems.indexOf(t);this.activeItems.splice(e,1),kt(t,"active")}clearActiveItems(){kt(this.activeItems,"active"),this.activeItems=[]}setActiveOption(t,e=!0){t!==this.activeOption&&(this.clearActiveOption(),t&&(this.activeOption=t,Ot(this.focus_node,{"aria-activedescendant":t.getAttribute("id")}),Ot(t,{"aria-selected":"true"}),wt(t,"active"),e&&this.scrollToOption(t)))}scrollToOption(t,e){if(!t)return;const n=this.dropdown_content,i=n.clientHeight,o=n.scrollTop||0,r=t.offsetHeight,s=t.getBoundingClientRect().top-n.getBoundingClientRect().top+o;s+r>i+o?this.scroll(s-i+r,e):s{t.setActiveItemClass(e)})))}inputState(){var t=this;t.control.contains(t.control_input)&&(Ot(t.control_input,{placeholder:t.settings.placeholder}),t.activeItems.length>0||!t.isFocused&&t.settings.hidePlaceholder&&t.items.length>0?(t.setTextboxValue(),t.isInputHidden=!0):(t.settings.hidePlaceholder&&t.items.length>0&&Ot(t.control_input,{placeholder:""}),t.isInputHidden=!1),t.wrapper.classList.toggle("input-hidden",t.isInputHidden))}inputValue(){return this.control_input.value.trim()}focus(){var t=this;t.isDisabled||t.isReadOnly||(t.ignoreFocus=!0,t.control_input.offsetWidth?t.control_input.focus():t.focus_node.focus(),setTimeout((()=>{t.ignoreFocus=!1,t.onFocus()}),0))}blur(){this.focus_node.blur(),this.onBlur()}getScoreFunction(t){return this.sifter.getScoreFunction(t,this.getSearchOptions())}getSearchOptions(){var t=this.settings,e=t.sortField;return"string"==typeof t.sortField&&(e=[{field:t.sortField}]),{fields:t.searchField,conjunction:t.searchConjunction,sort:e,nesting:t.nesting}}search(t){var e,n,i=this,o=this.getSearchOptions();if(i.settings.score&&"function"!=typeof(n=i.settings.score.call(i,t)))throw new Error('Tom Select "score" setting must be a function that returns a function');return t!==i.lastQuery?(i.lastQuery=t,e=i.sifter.search(t,Object.assign(o,{score:n})),i.currentResults=e):e=Object.assign({},i.currentResults),i.settings.hideSelected&&(e.items=e.items.filter((t=>{let e=rt(t.id);return!(e&&-1!==i.items.indexOf(e))}))),e}refreshOptions(t=!0){var e,n,i,o,r,s,a,l,c,u;const d={},h=[];var p=this,m=p.inputValue();const f=m===p.lastQuery||""==m&&null==p.lastQuery;var g=p.search(m),v=null,y=p.settings.shouldOpen||!1,b=p.dropdown_content;f&&(v=p.activeOption)&&(c=v.closest("[data-group]")),o=g.items.length,"number"==typeof p.settings.maxOptions&&(o=Math.min(o,p.settings.maxOptions)),o>0&&(y=!0);const _=(t,e)=>{let n=d[t];if(void 0!==n){let t=h[n];if(void 0!==t)return[n,t.fragment]}let i=document.createDocumentFragment();return n=h.length,h.push({fragment:i,order:e,optgroup:t}),[n,i]};for(e=0;e0&&(u=u.cloneNode(!0),Ot(u,{id:a.$id+"-clone-"+n,"aria-selected":null}),u.classList.add("ts-cloned"),kt(u,"active"),p.activeOption&&p.activeOption.dataset.value==o&&c&&c.dataset.group===r.toString()&&(v=u)),l.appendChild(u),""!=r&&(d[r]=i)}}var w;p.settings.lockOptgroupOrder&&h.sort(((t,e)=>t.order-e.order)),a=document.createDocumentFragment(),gt(h,(t=>{let e=t.fragment,n=t.optgroup;if(!e||!e.children.length)return;let i=p.optgroups[n];if(void 0!==i){let t=document.createDocumentFragment(),n=p.render("optgroup_header",i);ft(t,n),ft(t,e);let o=p.render("optgroup",{group:i,options:t});ft(a,o)}else ft(a,e)})),b.innerHTML="",ft(b,a),p.settings.highlight&&(w=b.querySelectorAll("span.highlight"),Array.prototype.forEach.call(w,(function(t){var e=t.parentNode;e.replaceChild(t.firstChild,t),e.normalize()})),g.query.length&&g.tokens.length&>(g.tokens,(t=>{Lt(b,t.regex)})));var k=t=>{let e=p.render(t,{input:m});return e&&(y=!0,b.insertBefore(e,b.firstChild)),e};if(p.loading?k("loading"):p.settings.shouldLoad.call(p,m)?0===g.items.length&&k("no_results"):k("not_loading"),(l=p.canCreate(m))&&(u=k("option_create")),p.hasOptions=g.items.length>0||l,y){if(g.items.length>0){if(v||"single"!==p.settings.mode||null==p.items[0]||(v=p.getOption(p.items[0])),!b.contains(v)){let t=0;u&&!p.settings.addPrecedence&&(t=1),v=p.selectable()[t]}}else u&&(v=u);t&&!p.isOpen&&(p.open(),p.scrollToOption(v,"auto")),p.setActiveOption(v)}else p.clearActiveOption(),t&&p.isOpen&&p.close(!1)}selectable(){return this.dropdown_content.querySelectorAll("[data-selectable]")}addOption(t,e=!1){const n=this;if(Array.isArray(t))return n.addOptions(t,e),!1;const i=rt(t[n.settings.valueField]);return null!==i&&!n.options.hasOwnProperty(i)&&(t.$order=t.$order||++n.order,t.$id=n.inputId+"-opt-"+t.$order,n.options[i]=t,n.lastQuery=null,e&&(n.userOptions[i]=e,n.trigger("option_add",i,t)),i)}addOptions(t,e=!1){gt(t,(t=>{this.addOption(t,e)}))}registerOption(t){return this.addOption(t)}registerOptionGroup(t){var e=rt(t[this.settings.optgroupValueField]);return null!==e&&(t.$order=t.$order||++this.order,this.optgroups[e]=t,e)}addOptionGroup(t,e){var n;e[this.settings.optgroupValueField]=t,(n=this.registerOptionGroup(e))&&this.trigger("optgroup_add",n,e)}removeOptionGroup(t){this.optgroups.hasOwnProperty(t)&&(delete this.optgroups[t],this.clearCache(),this.trigger("optgroup_remove",t))}clearOptionGroups(){this.optgroups={},this.clearCache(),this.trigger("optgroup_clear")}updateOption(t,e){const n=this;var i,o;const r=rt(t),s=rt(e[n.settings.valueField]);if(null===r)return;const a=n.options[r];if(null==a)return;if("string"!=typeof s)throw new Error("Value must be set in option data");const l=n.getOption(r),c=n.getItem(r);if(e.$order=e.$order||a.$order,delete n.options[r],n.uncacheValue(s),n.options[s]=e,l){if(n.dropdown_content.contains(l)){const t=n._render("option",e);Ct(l,t),n.activeOption===l&&n.setActiveOption(t)}l.remove()}c&&(-1!==(o=n.items.indexOf(r))&&n.items.splice(o,1,s),i=n._render("item",e),c.classList.contains("active")&&wt(i,"active"),Ct(c,i)),n.lastQuery=null}removeOption(t,e){const n=this;t=st(t),n.uncacheValue(t),delete n.userOptions[t],delete n.options[t],n.lastQuery=null,n.trigger("option_remove",t),n.removeItem(t,e)}clearOptions(t){const e=(t||this.clearFilter).bind(this);this.loadedSearches={},this.userOptions={},this.clearCache();const n={};gt(this.options,((t,i)=>{e(t,i)&&(n[i]=t)})),this.options=this.sifter.items=n,this.lastQuery=null,this.trigger("option_clear")}clearFilter(t,e){return this.items.indexOf(e)>=0}getOption(t,e=!1){const n=rt(t);if(null===n)return null;const i=this.options[n];if(null!=i){if(i.$div)return i.$div;if(e)return this._render("option",i)}return null}getAdjacent(t,e,n="option"){var i;if(!t)return null;i="item"==n?this.controlChildren():this.dropdown_content.querySelectorAll("[data-selectable]");for(let n=0;n0?i[n+1]:i[n-1];return null}getItem(t){if("object"==typeof t)return t;var e=rt(t);return null!==e?this.control.querySelector(`[data-value="${mt(e)}"]`):null}addItems(t,e){var n=this,i=Array.isArray(t)?t:[t];const o=(i=i.filter((t=>-1===n.items.indexOf(t))))[i.length-1];i.forEach((t=>{n.isPending=t!==o,n.addItem(t,e)}))}addItem(t,e){ct(this,e?[]:["change","dropdown_close"],(()=>{var n,i;const o=this,r=o.settings.mode,s=rt(t);if((!s||-1===o.items.indexOf(s)||("single"===r&&o.close(),"single"!==r&&o.settings.duplicates))&&null!==s&&o.options.hasOwnProperty(s)&&("single"===r&&o.clear(e),"multi"!==r||!o.isFull())){if(n=o._render("item",o.options[s]),o.control.contains(n)&&(n=n.cloneNode(!0)),i=o.isFull(),o.items.splice(o.caretPos,0,s),o.insertAtCaret(n),o.isSetup){if(!o.isPending&&o.settings.hideSelected){let t=o.getOption(s),e=o.getAdjacent(t,1);e&&o.setActiveOption(e)}o.isPending||o.settings.closeAfterSelect||o.refreshOptions(o.isFocused&&"single"!==r),0!=o.settings.closeAfterSelect&&o.isFull()?o.close():o.isPending||o.positionDropdown(),o.trigger("item_add",s,n),o.isPending||o.updateOriginalInput({silent:e})}(!o.isPending||!i&&o.isFull())&&(o.inputState(),o.refreshState())}}))}removeItem(t=null,e){const n=this;if(!(t=n.getItem(t)))return;var i,o;const r=t.dataset.value;i=xt(t),t.remove(),t.classList.contains("active")&&(o=n.activeItems.indexOf(t),n.activeItems.splice(o,1),kt(t,"active")),n.items.splice(i,1),n.lastQuery=null,!n.settings.persist&&n.userOptions.hasOwnProperty(r)&&n.removeOption(r,e),i{})){3===arguments.length&&(e=arguments[2]),"function"!=typeof e&&(e=()=>{});var n,i=this,o=i.caretPos;if(t=t||i.inputValue(),!i.canCreate(t))return e(),!1;i.lock();var r=!1,s=t=>{if(i.unlock(),!t||"object"!=typeof t)return e();var n=rt(t[i.settings.valueField]);if("string"!=typeof n)return e();i.setTextboxValue(),i.addOption(t,!0),i.setCaret(o),i.addItem(n),e(t),r=!0};return n="function"==typeof i.settings.create?i.settings.create.call(this,t,s):{[i.settings.labelField]:t,[i.settings.valueField]:t},r||s(n),!0}refreshItems(){var t=this;t.lastQuery=null,t.isSetup&&t.addItems(t.items),t.updateOriginalInput(),t.refreshState()}refreshState(){const t=this;t.refreshValidityState();const e=t.isFull(),n=t.isLocked;t.wrapper.classList.toggle("rtl",t.rtl);const i=t.wrapper.classList;var o;i.toggle("focus",t.isFocused),i.toggle("disabled",t.isDisabled),i.toggle("readonly",t.isReadOnly),i.toggle("required",t.isRequired),i.toggle("invalid",!t.isValid),i.toggle("locked",n),i.toggle("full",e),i.toggle("input-active",t.isFocused&&!t.isInputHidden),i.toggle("dropdown-active",t.isOpen),i.toggle("has-options",(o=t.options,0===Object.keys(o).length)),i.toggle("has-items",t.items.length>0)}refreshValidityState(){var t=this;t.input.validity&&(t.isValid=t.input.validity.valid,t.isInvalid=!t.isValid)}isFull(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems}updateOriginalInput(t={}){const e=this;var n,i;const o=e.input.querySelector('option[value=""]');if(e.is_select_tag){const r=[],s=e.input.querySelectorAll("option:checked").length;function a(t,n,i){return t||(t=vt('")),t!=o&&e.input.append(t),r.push(t),(t!=o||s>0)&&(t.selected=!0),t}e.input.querySelectorAll("option:checked").forEach((t=>{t.selected=!1})),0==e.items.length&&"single"==e.settings.mode?a(o,"",""):e.items.forEach((t=>{if(n=e.options[t],i=n[e.settings.labelField]||"",r.includes(n.$option)){a(e.input.querySelector(`option[value="${mt(t)}"]:not(:checked)`),t,i)}else n.$option=a(n.$option,t,i)}))}else e.input.value=e.getValue();e.isSetup&&(t.silent||e.trigger("change",e.getValue()))}open(){var t=this;t.isLocked||t.isOpen||"multi"===t.settings.mode&&t.isFull()||(t.isOpen=!0,Ot(t.focus_node,{"aria-expanded":"true"}),t.refreshState(),_t(t.dropdown,{visibility:"hidden",display:"block"}),t.positionDropdown(),_t(t.dropdown,{visibility:"visible",display:"block"}),t.focus(),t.trigger("dropdown_open",t.dropdown))}close(t=!0){var e=this,n=e.isOpen;t&&(e.setTextboxValue(),"single"===e.settings.mode&&e.items.length&&e.inputState()),e.isOpen=!1,Ot(e.focus_node,{"aria-expanded":"false"}),_t(e.dropdown,{display:"none"}),e.settings.hideSelected&&e.clearActiveOption(),e.refreshState(),n&&e.trigger("dropdown_close",e.dropdown)}positionDropdown(){if("body"===this.settings.dropdownParent){var t=this.control,e=t.getBoundingClientRect(),n=t.offsetHeight+e.top+window.scrollY,i=e.left+window.scrollX;_t(this.dropdown,{width:e.width+"px",top:n+"px",left:i+"px"})}}clear(t){var e=this;if(e.items.length){var n=e.controlChildren();gt(n,(t=>{e.removeItem(t,!0)})),e.inputState(),t||e.updateOriginalInput(),e.trigger("clear")}}insertAtCaret(t){const e=this,n=e.caretPos,i=e.control;i.insertBefore(t,i.children[n]||null),e.setCaret(n+1)}deleteSelection(t){var e,n,i,o,r,s=this;e=t&&8===t.keyCode?-1:1,n={start:(r=s.control_input).selectionStart||0,length:(r.selectionEnd||0)-(r.selectionStart||0)};const a=[];if(s.activeItems.length)o=St(s.activeItems,e),i=xt(o),e>0&&i++,gt(s.activeItems,(t=>a.push(t)));else if((s.isFocused||"single"===s.settings.mode)&&s.items.length){const t=s.controlChildren();let i;e<0&&0===n.start&&0===n.length?i=t[s.caretPos-1]:e>0&&n.start===s.inputValue().length&&(i=t[s.caretPos]),void 0!==i&&a.push(i)}if(!s.shouldDelete(a,t))return!1;for(ut(t,!0),void 0!==i&&s.setCaret(i);a.length;)s.removeItem(a.pop());return s.inputState(),s.positionDropdown(),s.refreshOptions(!1),!0}shouldDelete(t,e){const n=t.map((t=>t.dataset.value));return!(!n.length||"function"==typeof this.settings.onDelete&&!1===this.settings.onDelete(n,e))}advanceSelection(t,e){var n,i,o=this;o.rtl&&(t*=-1),o.inputValue().length||(ht(Mt,e)||ht("shiftKey",e)?(i=(n=o.getLastActive(t))?n.classList.contains("active")?o.getAdjacent(n,t,"item"):n:t>0?o.control_input.nextElementSibling:o.control_input.previousElementSibling)&&(i.classList.contains("active")&&o.removeActiveItem(n),o.setActiveItemClass(i)):o.moveCaret(t))}moveCaret(t){}getLastActive(t){let e=this.control.querySelector(".last-active");if(e)return e;var n=this.control.querySelectorAll(".active");return n?St(n,t):void 0}setCaret(t){this.caretPos=this.items.length}controlChildren(){return Array.from(this.control.querySelectorAll("[data-ts-item]"))}lock(){this.setLocked(!0)}unlock(){this.setLocked(!1)}setLocked(t=this.isReadOnly||this.isDisabled){this.isLocked=t,this.refreshState()}disable(){this.setDisabled(!0),this.close()}enable(){this.setDisabled(!1)}setDisabled(t){this.focus_node.tabIndex=t?-1:this.tabIndex,this.isDisabled=t,this.input.disabled=t,this.control_input.disabled=t,this.setLocked()}setReadOnly(t){this.isReadOnly=t,this.input.readOnly=t,this.control_input.readOnly=t,this.setLocked()}destroy(){var t=this,e=t.revertSettings;t.trigger("destroy"),t.off(),t.wrapper.remove(),t.dropdown.remove(),t.input.innerHTML=e.innerHTML,t.input.tabIndex=e.tabIndex,kt(t.input,"tomselected","ts-hidden-accessible"),t._destroy(),delete t.input.tomselect}render(t,e){var n,i;const o=this;if("function"!=typeof this.settings.render[t])return null;if(!(i=o.settings.render[t].call(this,e,at)))return null;if(i=vt(i),"option"===t||"option_create"===t?e[o.settings.disabledField]?Ot(i,{"aria-disabled":"true"}):Ot(i,{"data-selectable":""}):"optgroup"===t&&(n=e.group[o.settings.optgroupValueField],Ot(i,{"data-group":n}),e.group[o.settings.disabledField]&&Ot(i,{"data-disabled":""})),"option"===t||"item"===t){const n=st(e[o.settings.valueField]);Ot(i,{"data-value":n}),"item"===t?(wt(i,o.settings.itemClass),Ot(i,{"data-ts-item":""})):(wt(i,o.settings.optionClass),Ot(i,{role:"option",id:e.$id}),e.$div=i,o.options[n]=e)}return i}_render(t,e){const n=this.render(t,e);if(null==n)throw"HTMLElement expected";return n}clearCache(){gt(this.options,(t=>{t.$div&&(t.$div.remove(),delete t.$div)}))}uncacheValue(t){const e=this.getOption(t);e&&e.remove()}canCreate(t){return this.settings.create&&t.length>0&&this.settings.createFilter.call(this,t)}hook(t,e,n){var i=this,o=i[e];i[e]=function(){var e,r;return"after"===t&&(e=o.apply(i,arguments)),r=n.apply(i,arguments),"instead"===t?r:("before"===t&&(e=o.apply(i,arguments)),e)}}}const Ft=t=>"boolean"==typeof t?t?"1":"0":t+"",jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},qt=t=>"string"==typeof t&&t.indexOf("<")>-1;const Ht=t=>"string"==typeof t&&t.indexOf("<")>-1;const Vt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Rt=t=>"string"==typeof t&&t.indexOf("<")>-1,Bt=(t,e)=>{((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(e,((e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)}))};const $t=t=>"string"==typeof t&&t.indexOf("<")>-1;const Wt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Yt=t=>(Array.isArray(t)||(t=[t]),t);const zt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Ut(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},Ut=t=>"string"==typeof t&&t.indexOf("<")>-1,Zt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Xt=t=>(Array.isArray(t)||(t=[t]),t);const Kt=(t,e,n,i)=>{t.addEventListener(e,n,i)};const Jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Gt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Qt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(te(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},te=t=>"string"==typeof t&&t.indexOf("<")>-1;const ee=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},ne=t=>(Array.isArray(t)||(t=[t]),t);Pt.define("change_listener",(function(){var t,e,n,i;t=this.input,e="change",n=()=>{this.sync()},t.addEventListener(e,n,i)})),Pt.define("checkbox_options",(function(t){var e=this,n=e.onOptionSelect;e.settings.hideSelected=!1;const i=Object.assign({className:"tomselect-checkbox",checkedClassNames:void 0,uncheckedClassNames:void 0},t);var o=function(t,e){e?(t.checked=!0,i.uncheckedClassNames&&t.classList.remove(...i.uncheckedClassNames),i.checkedClassNames&&t.classList.add(...i.checkedClassNames)):(t.checked=!1,i.checkedClassNames&&t.classList.remove(...i.checkedClassNames),i.uncheckedClassNames&&t.classList.add(...i.uncheckedClassNames))},r=function(t){setTimeout((()=>{var e=t.querySelector("input."+i.className);e instanceof HTMLInputElement&&o(e,t.classList.contains("selected"))}),1)};e.hook("after","setupTemplates",(()=>{var t=e.settings.render.option;e.settings.render.option=(n,r)=>{var s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(qt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(t.call(e,n,r)),a=document.createElement("input");i.className&&a.classList.add(i.className),a.addEventListener("click",(function(t){jt(t)})),a.type="checkbox";const l=null==(c=n[e.settings.valueField])?null:Ft(c);var c;return o(a,!!(l&&e.items.indexOf(l)>-1)),s.prepend(a),s}})),e.on("item_remove",(t=>{var n=e.getOption(t);n&&(n.classList.remove("selected"),r(n))})),e.on("item_add",(t=>{var n=e.getOption(t);n&&r(n)})),e.hook("instead","onOptionSelect",((t,i)=>{if(i.classList.contains("selected"))return i.classList.remove("selected"),e.removeItem(i.dataset.value),e.refreshOptions(),void jt(t,!0);n.call(e,t,i),r(i)}))})),Pt.define("clear_button",(function(t){const e=this,n=Object.assign({className:"clear-button",title:"Clear All",html:t=>`
⨯
`},t);e.on("initialize",(()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Ht(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n));t.addEventListener("click",(t=>{e.isLocked||(e.clear(),"single"===e.settings.mode&&e.settings.allowEmptyOption&&e.addItem(""),t.preventDefault(),t.stopPropagation())})),e.control.appendChild(t)}))})),Pt.define("drag_drop",(function(){var t=this;if("multi"!==t.settings.mode)return;var e=t.lock,n=t.unlock;let i,o=!0;t.hook("after","setupTemplates",(()=>{var e=t.settings.render.item;t.settings.render.item=(n,r)=>{const s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Rt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(e.call(t,n,r));Bt(s,{draggable:"true"});const a=t=>{t.preventDefault(),s.classList.add("ts-drag-over"),l(s,i)},l=(t,e)=>{var n,i,o;void 0!==e&&(((t,e)=>{do{var n;if(t==(e=null==(n=e)?void 0:n.previousElementSibling))return!0}while(e&&e.previousElementSibling);return!1})(e,s)?(i=e,null==(o=(n=t).parentNode)||o.insertBefore(i,n.nextSibling)):((t,e)=>{var n;null==(n=t.parentNode)||n.insertBefore(e,t)})(t,e))};return Vt(s,"mousedown",(t=>{o||((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t),t.stopPropagation()})),Vt(s,"dragstart",(t=>{i=s,setTimeout((()=>{s.classList.add("ts-dragging")}),0)})),Vt(s,"dragenter",a),Vt(s,"dragover",a),Vt(s,"dragleave",(()=>{s.classList.remove("ts-drag-over")})),Vt(s,"dragend",(()=>{var e;document.querySelectorAll(".ts-drag-over").forEach((t=>t.classList.remove("ts-drag-over"))),null==(e=i)||e.classList.remove("ts-dragging"),i=void 0;var n=[];t.control.querySelectorAll("[data-value]").forEach((t=>{if(t.dataset.value){let e=t.dataset.value;e&&n.push(e)}})),t.setValue(n)})),s}})),t.hook("instead","lock",(()=>(o=!1,e.call(t)))),t.hook("instead","unlock",(()=>(o=!0,n.call(t))))})),Pt.define("dropdown_header",(function(t){const e=this,n=Object.assign({title:"Untitled",headerClass:"dropdown-header",titleRowClass:"dropdown-header-title",labelClass:"dropdown-header-label",closeClass:"dropdown-header-close",html:t=>'
'+t.title+'×
'},t);e.on("initialize",(()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if($t(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n)),i=t.querySelector("."+n.closeClass);i&&i.addEventListener("click",(t=>{((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t,!0),e.close()})),e.dropdown.insertBefore(t,e.dropdown.firstChild)}))})),Pt.define("caret_position",(function(){var t=this;t.hook("instead","setCaret",(e=>{"single"!==t.settings.mode&&t.control.contains(t.control_input)?(e=Math.max(0,Math.min(t.items.length,e)))==t.caretPos||t.isPending||t.controlChildren().forEach(((n,i)=>{i{if(!t.isFocused)return;const n=t.getLastActive(e);if(n){const i=((t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n})(n);t.setCaret(e>0?i+1:i),t.setActiveItem(),((t,...e)=>{var n=Wt(e);(t=Yt(t)).map((t=>{n.map((e=>{t.classList.remove(e)}))}))})(n,"last-active")}else t.setCaret(t.caretPos+e)}))})),Pt.define("dropdown_input",(function(){const t=this;t.settings.shouldOpen=!0,t.hook("before","setup",(()=>{t.focus_node=t.control,((t,...e)=>{var n=Zt(e);(t=Xt(t)).map((t=>{n.map((e=>{t.classList.add(e)}))}))})(t.control_input,"dropdown-input");const e=zt('");for(var T=1;T<=7;T+=1){var S=3+this.options.firstDay+T,x=document.createElement("div");x.innerHTML=this.weekdayName(S),x.title=this.weekdayName(S,"long"),D.appendChild(x)}var O=document.createElement("div");O.className=a.containerDays;var C=this.calcSkipDays(i);this.options.showWeekNumbers&&C&&O.appendChild(this.renderWeekNumber(i));for(var L=0;L1&&1===this.datePicked.length){var o=this.options.minDays-1,r=this.datePicked[0].clone().subtract(o,"day"),c=this.datePicked[0].clone().add(o,"day");t.isBetween(r,this.datePicked[0],"(]")&&e.classList.add(a.isLocked),t.isBetween(this.datePicked[0],c,"[)")&&e.classList.add(a.isLocked)}if(this.options.maxDays&&1===this.datePicked.length){var u=this.options.maxDays;r=this.datePicked[0].clone().subtract(u,"day"),c=this.datePicked[0].clone().add(u,"day"),t.isSameOrBefore(r)&&e.classList.add(a.isLocked),t.isSameOrAfter(c)&&e.classList.add(a.isLocked)}return this.options.selectForward&&1===this.datePicked.length&&t.isBefore(this.datePicked[0])&&e.classList.add(a.isLocked),this.options.selectBackward&&1===this.datePicked.length&&t.isAfter(this.datePicked[0])&&e.classList.add(a.isLocked),l.dateIsLocked(t,this.options,this.datePicked)&&e.classList.add(a.isLocked),this.options.highlightedDays.length&&this.options.highlightedDays.filter((function(e){return e instanceof Array?t.isBetween(e[0],e[1],"[]"):e.isSame(t,"day")})).length&&e.classList.add(a.isHighlighted),e.tabIndex=e.classList.contains("is-locked")?-1:0,this.emit("render:day",e,t),e},e.prototype.renderFooter=function(){var t=document.createElement("div");if(t.className=a.containerFooter,this.options.footerHTML?t.innerHTML=this.options.footerHTML:t.innerHTML='\n \n \n \n ",this.options.singleMode){if(1===this.datePicked.length){var e=this.datePicked[0].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=e}}else if(1===this.datePicked.length&&t.querySelector("."+a.buttonApply).setAttribute("disabled",""),2===this.datePicked.length){e=this.datePicked[0].format(this.options.format,this.options.lang);var n=this.datePicked[1].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=""+e+this.options.delimiter+n}return this.emit("render:footer",t),t},e.prototype.renderWeekNumber=function(t){var e=document.createElement("div"),n=t.getWeek(this.options.firstDay);return e.className=a.weekNumber,e.innerHTML=53===n&&0===t.getMonth()?"53 / 1":n,e},e.prototype.renderTooltip=function(){var t=document.createElement("div");return t.className=a.containerTooltip,t},e.prototype.weekdayName=function(t,e){return void 0===e&&(e="short"),new Date(1970,0,t,12,0,0,0).toLocaleString(this.options.lang,{weekday:e})},e.prototype.calcSkipDays=function(t){var e=t.getDay()-this.options.firstDay;return e<0&&(e+=7),e},e}(r.LPCore);e.Calendar=c},function(t,e,n){"use strict";var i,o=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),r=this&&this.__assign||function(){return(r=Object.assign||function(t){for(var e,n=1,i=arguments.length;n',nextMonth:'',reset:'\n \n \n '},tooltipText:{one:"day",other:"days"}},n.options=r(r({},n.options),e.element.dataset),Object.keys(n.options).forEach((function(t){"true"!==n.options[t]&&"false"!==n.options[t]||(n.options[t]="true"===n.options[t])}));var i=r(r({},n.options.dropdowns),e.dropdowns),o=r(r({},n.options.buttonText),e.buttonText),s=r(r({},n.options.tooltipText),e.tooltipText);n.options=r(r({},n.options),e),n.options.dropdowns=r({},i),n.options.buttonText=r({},o),n.options.tooltipText=r({},s),n.options.elementEnd||(n.options.allowRepick=!1),n.options.lockDays.length&&(n.options.lockDays=a.DateTime.convertArray(n.options.lockDays,n.options.lockDaysFormat)),n.options.highlightedDays.length&&(n.options.highlightedDays=a.DateTime.convertArray(n.options.highlightedDays,n.options.highlightedDaysFormat));var l=n.parseInput(),c=l[0],u=l[1];n.options.startDate&&(n.options.singleMode||n.options.endDate)&&(c=new a.DateTime(n.options.startDate,n.options.format,n.options.lang)),c&&n.options.endDate&&(u=new a.DateTime(n.options.endDate,n.options.format,n.options.lang)),c instanceof a.DateTime&&!isNaN(c.getTime())&&(n.options.startDate=c),n.options.startDate&&u instanceof a.DateTime&&!isNaN(u.getTime())&&(n.options.endDate=u),!n.options.singleMode||n.options.startDate instanceof a.DateTime||(n.options.startDate=null),n.options.singleMode||n.options.startDate instanceof a.DateTime&&n.options.endDate instanceof a.DateTime||(n.options.startDate=null,n.options.endDate=null);for(var d=0;dwindow.innerHeight,c=e.top+r-n.height>=n.height;l&&c&&(s=e.top+r-n.height)}if(/left|right/.test(i[0])||i[1]&&"auto"!==i[1]&&/left|right/.test(i[1]))a=/left|right/.test(i[0])?e[i[0]]+o:e[i[1]]+o,"right"!==i[0]&&"right"!==i[1]||(a-=n.width);else{a=e.left+o,l=e.left+n.width>window.innerWidth;var u=e.right+o-n.width>=0;l&&u&&(a=e.right+o-n.width)}return{left:a,top:s}},e}(s.EventEmitter);e.LPCore=c},function(t,e,n){"use strict";var i,o="object"==typeof Reflect?Reflect:null,r=o&&"function"==typeof o.apply?o.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};i=o&&"function"==typeof o.ownKeys?o.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var l=10;function c(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function u(t,e,n,i){var o,r,s,a;if("function"!=typeof n)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof n);if(void 0===(r=t._events)?(r=t._events=Object.create(null),t._eventsCount=0):(void 0!==r.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),r=t._events),s=r[e]),void 0===s)s=r[e]=n,++t._eventsCount;else if("function"==typeof s?s=r[e]=i?[n,s]:[s,n]:i?s.unshift(n):s.push(n),(o=c(t))>0&&s.length>o&&!s.warned){s.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=t,l.type=e,l.count=s.length,a=l,console&&console.warn&&console.warn(a)}return t}function d(){for(var t=[],e=0;e0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var l=o[t];if(void 0===l)return!1;if("function"==typeof l)r(l,this,e);else{var c=l.length,u=f(l,c);for(n=0;n=0;r--)if(n[r]===e||n[r].listener===e){s=n[r].listener,o=r;break}if(o<0)return this;0===o?n.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},a.prototype.listeners=function(t){return p(this,t,!0)},a.prototype.rawListeners=function(t){return p(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):m.call(t,e)},a.prototype.listenerCount=m,a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(t,e,n){(e=n(9)(!1)).push([t.i,':root{--litepicker-container-months-color-bg: #fff;--litepicker-container-months-box-shadow-color: #ddd;--litepicker-footer-color-bg: #fafafa;--litepicker-footer-box-shadow-color: #ddd;--litepicker-tooltip-color-bg: #fff;--litepicker-month-header-color: #333;--litepicker-button-prev-month-color: #9e9e9e;--litepicker-button-next-month-color: #9e9e9e;--litepicker-button-prev-month-color-hover: #2196f3;--litepicker-button-next-month-color-hover: #2196f3;--litepicker-month-width: calc(var(--litepicker-day-width) * 7);--litepicker-month-weekday-color: #9e9e9e;--litepicker-month-week-number-color: #9e9e9e;--litepicker-day-width: 38px;--litepicker-day-color: #333;--litepicker-day-color-hover: #2196f3;--litepicker-is-today-color: #f44336;--litepicker-is-in-range-color: #bbdefb;--litepicker-is-locked-color: #9e9e9e;--litepicker-is-start-color: #fff;--litepicker-is-start-color-bg: #2196f3;--litepicker-is-end-color: #fff;--litepicker-is-end-color-bg: #2196f3;--litepicker-button-cancel-color: #fff;--litepicker-button-cancel-color-bg: #9e9e9e;--litepicker-button-apply-color: #fff;--litepicker-button-apply-color-bg: #2196f3;--litepicker-button-reset-color: #909090;--litepicker-button-reset-color-hover: #2196f3;--litepicker-highlighted-day-color: #333;--litepicker-highlighted-day-color-bg: #ffeb3b}.show-week-numbers{--litepicker-month-width: calc(var(--litepicker-day-width) * 8)}.litepicker{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-size:0.8em;display:none}.litepicker button{border:none;background:none}.litepicker .container__main{display:-webkit-box;display:-ms-flexbox;display:flex}.litepicker .container__months{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background-color:var(--litepicker-container-months-color-bg);border-radius:5px;-webkit-box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);width:calc(var(--litepicker-month-width) + 10px);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months.columns-2{width:calc((var(--litepicker-month-width) * 2) + 20px)}.litepicker .container__months.columns-3{width:calc((var(--litepicker-month-width) * 3) + 30px)}.litepicker .container__months.columns-4{width:calc((var(--litepicker-month-width) * 4) + 40px)}.litepicker .container__months.split-view .month-item-header .button-previous-month,.litepicker .container__months.split-view .month-item-header .button-next-month{visibility:visible}.litepicker .container__months .month-item{padding:5px;width:var(--litepicker-month-width);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months .month-item-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-weight:500;padding:10px 5px;text-align:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--litepicker-month-header-color)}.litepicker .container__months .month-item-header div{-webkit-box-flex:1;-ms-flex:1;flex:1}.litepicker .container__months .month-item-header div>.month-item-name{margin-right:5px}.litepicker .container__months .month-item-header div>.month-item-year{padding:0}.litepicker .container__months .month-item-header .reset-button{color:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button>svg{fill:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button *{pointer-events:none}.litepicker .container__months .month-item-header .reset-button:hover{color:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .reset-button:hover>svg{fill:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .button-previous-month,.litepicker .container__months .month-item-header .button-next-month{visibility:hidden;text-decoration:none;padding:3px 5px;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__months .month-item-header .button-previous-month *,.litepicker .container__months .month-item-header .button-next-month *{pointer-events:none}.litepicker .container__months .month-item-header .button-previous-month{color:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month>svg,.litepicker .container__months .month-item-header .button-previous-month>img{fill:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month:hover{color:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-previous-month:hover>svg{fill:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month{color:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month>svg,.litepicker .container__months .month-item-header .button-next-month>img{fill:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month:hover{color:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month:hover>svg{fill:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-weekdays-row{display:-webkit-box;display:-ms-flexbox;display:flex;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;color:var(--litepicker-month-weekday-color)}.litepicker .container__months .month-item-weekdays-row>div{padding:5px 0;font-size:85%;-webkit-box-flex:1;-ms-flex:1;flex:1;width:var(--litepicker-day-width);text-align:center}.litepicker .container__months .month-item:first-child .button-previous-month{visibility:visible}.litepicker .container__months .month-item:last-child .button-next-month{visibility:visible}.litepicker .container__months .month-item.no-previous-month .button-previous-month{visibility:hidden}.litepicker .container__months .month-item.no-next-month .button-next-month{visibility:hidden}.litepicker .container__days{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;text-align:center;-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__days>div,.litepicker .container__days>a{padding:5px 0;width:var(--litepicker-day-width)}.litepicker .container__days .day-item{color:var(--litepicker-day-color);text-align:center;text-decoration:none;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__days .day-item:hover{color:var(--litepicker-day-color-hover);-webkit-box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover);box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover)}.litepicker .container__days .day-item.is-today{color:var(--litepicker-is-today-color)}.litepicker .container__days .day-item.is-locked{color:var(--litepicker-is-locked-color)}.litepicker .container__days .day-item.is-locked:hover{color:var(--litepicker-is-locked-color);-webkit-box-shadow:none;box-shadow:none;cursor:default}.litepicker .container__days .day-item.is-in-range{background-color:var(--litepicker-is-in-range-color);border-radius:0}.litepicker .container__days .day-item.is-start-date{color:var(--litepicker-is-start-color);background-color:var(--litepicker-is-start-color-bg);border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-flipped{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date{color:var(--litepicker-is-end-color);background-color:var(--litepicker-is-end-color-bg);border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date.is-flipped{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-end-date{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-highlighted{color:var(--litepicker-highlighted-day-color);background-color:var(--litepicker-highlighted-day-color-bg)}.litepicker .container__days .week-number{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:var(--litepicker-month-week-number-color);font-size:85%}.litepicker .container__footer{text-align:right;padding:10px 5px;margin:0 5px;background-color:var(--litepicker-footer-color-bg);-webkit-box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);border-bottom-left-radius:5px;border-bottom-right-radius:5px}.litepicker .container__footer .preview-date-range{margin-right:10px;font-size:90%}.litepicker .container__footer .button-cancel{background-color:var(--litepicker-button-cancel-color-bg);color:var(--litepicker-button-cancel-color);border:0;padding:3px 7px 4px;border-radius:3px}.litepicker .container__footer .button-cancel *{pointer-events:none}.litepicker .container__footer .button-apply{background-color:var(--litepicker-button-apply-color-bg);color:var(--litepicker-button-apply-color);border:0;padding:3px 7px 4px;border-radius:3px;margin-left:10px;margin-right:10px}.litepicker .container__footer .button-apply:disabled{opacity:0.7}.litepicker .container__footer .button-apply *{pointer-events:none}.litepicker .container__tooltip{position:absolute;margin-top:-4px;padding:4px 8px;border-radius:4px;background-color:var(--litepicker-tooltip-color-bg);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25);white-space:nowrap;font-size:11px;pointer-events:none;visibility:hidden}.litepicker .container__tooltip:before{position:absolute;bottom:-5px;left:calc(50% - 5px);border-top:5px solid rgba(0,0,0,0.12);border-right:5px solid transparent;border-left:5px solid transparent;content:""}.litepicker .container__tooltip:after{position:absolute;bottom:-4px;left:calc(50% - 4px);border-top:4px solid var(--litepicker-tooltip-color-bg);border-right:4px solid transparent;border-left:4px solid transparent;content:""}\n',""]),e.locals={showWeekNumbers:"show-week-numbers",litepicker:"litepicker",containerMain:"container__main",containerMonths:"container__months",columns2:"columns-2",columns3:"columns-3",columns4:"columns-4",splitView:"split-view",monthItemHeader:"month-item-header",buttonPreviousMonth:"button-previous-month",buttonNextMonth:"button-next-month",monthItem:"month-item",monthItemName:"month-item-name",monthItemYear:"month-item-year",resetButton:"reset-button",monthItemWeekdaysRow:"month-item-weekdays-row",noPreviousMonth:"no-previous-month",noNextMonth:"no-next-month",containerDays:"container__days",dayItem:"day-item",isToday:"is-today",isLocked:"is-locked",isInRange:"is-in-range",isStartDate:"is-start-date",isFlipped:"is-flipped",isEndDate:"is-end-date",isHighlighted:"is-highlighted",weekNumber:"week-number",containerFooter:"container__footer",previewDateRange:"preview-date-range",buttonCancel:"button-cancel",buttonApply:"button-apply",containerTooltip:"container__tooltip"},t.exports=e},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n,i,o,r=t[1]||"",s=t[3];if(!s)return r;if(e&&"function"==typeof btoa){var a=(n=s,i=btoa(unescape(encodeURIComponent(JSON.stringify(n)))),o="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(i),"/*# ".concat(o," */")),l=s.sources.map((function(t){return"/*# sourceURL=".concat(s.sourceRoot||"").concat(t," */")}));return[r].concat(l).concat([a]).join("\n")}return[r].join("\n")}(e,t);return e[2]?"@media ".concat(e[2]," {").concat(n,"}"):n})).join("")},e.i=function(t,n,i){"string"==typeof t&&(t=[[null,t,""]]);var o={};if(i)for(var r=0;rthis.options.endDate.getTime()&&(this.options.endDate=this.options.startDate.clone(),this.options.startDate=new o.DateTime(t,this.options.format,this.options.lang)),this.updateInput())},r.Litepicker.prototype.setDateRange=function(t,e,n){void 0===n&&(n=!1),this.triggerElement=void 0;var i=new o.DateTime(t,this.options.format,this.options.lang),r=new o.DateTime(e,this.options.format,this.options.lang);(this.options.disallowLockDaysInRange?s.rangeIsLocked([i,r],this.options):s.dateIsLocked(i,this.options,[i,r])||s.dateIsLocked(r,this.options,[i,r]))&&!n?this.emit("error:range",[i,r]):(this.setStartDate(i),this.setEndDate(r),this.options.inlineMode&&this.render(),this.updateInput(),this.emit("selected",this.getStartDate(),this.getEndDate()))},r.Litepicker.prototype.gotoDate=function(t,e){void 0===e&&(e=0);var n=new o.DateTime(t);n.setDate(1),this.calendars[e]=n.clone(),this.render()},r.Litepicker.prototype.setLockDays=function(t){this.options.lockDays=o.DateTime.convertArray(t,this.options.lockDaysFormat),this.render()},r.Litepicker.prototype.setHighlightedDays=function(t){this.options.highlightedDays=o.DateTime.convertArray(t,this.options.highlightedDaysFormat),this.render()},r.Litepicker.prototype.setOptions=function(t){delete t.element,delete t.elementEnd,delete t.parentEl,t.startDate&&(t.startDate=new o.DateTime(t.startDate,this.options.format,this.options.lang)),t.endDate&&(t.endDate=new o.DateTime(t.endDate,this.options.format,this.options.lang));var e=i(i({},this.options.dropdowns),t.dropdowns),n=i(i({},this.options.buttonText),t.buttonText),r=i(i({},this.options.tooltipText),t.tooltipText);this.options=i(i({},this.options),t),this.options.dropdowns=i({},e),this.options.buttonText=i({},n),this.options.tooltipText=i({},r),!this.options.singleMode||this.options.startDate instanceof o.DateTime||(this.options.startDate=null,this.options.endDate=null),this.options.singleMode||this.options.startDate instanceof o.DateTime&&this.options.endDate instanceof o.DateTime||(this.options.startDate=null,this.options.endDate=null);for(var s=0;s
'),null!==t.url){if(n+='"}this.createFromClickEvent(t,n)}createFromClickEvent(t,e){const n=this.getContextMenuElement();n.classList.contains("action-dropdown")||n.classList.add("action-dropdown"),n.innerHTML=e,n.style.position="fixed",n.style.top=t.clientY+"px",n.style.left=t.clientX+"px";const i=t=>{t.target.classList.contains("dropdown-toggle")||t.target.classList.contains("dropdown-divider")||(n.classList.remove("d-block"),n.classList.contains("d-none")||n.classList.add("d-none"),n.removeEventListener("click",i),document.removeEventListener("click",i))};n.addEventListener("click",i),document.addEventListener("click",i),n.classList.remove("d-none"),n.classList.contains("d-block")||n.classList.add("d-block")}static createForDataTable(t){[].slice.call(document.querySelectorAll(t)).map((t=>{null!==t.querySelector("td.actions div.dropdown-menu")&&t.addEventListener("contextmenu",(e=>{let n=e.target;for(;null!==n;){const t=n.tagName.toUpperCase();if("TH"===t||"TABLE"===t||"BODY"===t)return;if("TR"===t)break;n=n.parentNode}if(null===n||!n.matches("table.dataTable tbody tr"))return;const o=n.querySelector("td.actions div.dropdown-menu");if(null===o)return;e.preventDefault();new i(t.dataset.contextMenu).createFromClickEvent(e,o.innerHTML)}))}))}}},4028:function(t,e,n){n(4975),n(33),n.g.KimaiPaginatedBoxWidget=n(4100).A,n.g.KimaiReloadPageWidget=n(5170).A,n.g.KimaiColor=n(9997).A,n.g.KimaiStorage=n(5247).A},4100:function(t,e,n){"use strict";n.d(e,{A:function(){return o}});var i=n(2758);class o{constructor(t){this.selector=t;const e=document.querySelector(this.selector);if(void 0!==e.dataset.reload){this.events=e.dataset.reload.split(" ");const t=()=>{let t=null;t=void 0!==document.querySelector(this.selector).dataset.reloadHref?document.querySelector(this.selector).dataset.reloadHref:document.querySelector(this.selector+" ul.pagination li.active a").href,this.loadPage(t)};for(const e of this.events)document.addEventListener(e,t)}document.body.addEventListener("click",(t=>{let e=t.target;e.matches(this.selector+" a.pagination-link")||(e=e.parentNode),e.matches(this.selector+" a.pagination-link")&&(t.preventDefault(),this.loadPage(e.href))}))}static create(t){return new o(t)}loadPage(t){const e=this.selector;document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this.selector}));const n=()=>{document.dispatchEvent(new Event("kimai.reloadedContent"))};window.kimai.getPlugin("fetch").fetch(t).then((t=>{t.text().then((t=>{const o=document.createElement("div");o.innerHTML=t,document.querySelector(e).replaceWith(this._makeScriptExecutable(o.firstElementChild)),i.A.createForDataTable(e+" table.dataTable"),n()}))})).catch((()=>{window.kimai.getPlugin("alert").error("Failed loading selected page"),n()}))}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}}},4975:function(t,e,n){"use strict";n.r(e)},5170:function(t,e,n){"use strict";n.d(e,{A:function(){return i}});class i{constructor(t,e){const n=()=>{e?document.location.reload():this._loadPage(document.location)};for(const e of t.split(" "))document.addEventListener(e,n)}static create(t,e){return null==e&&(e=!1),new i(t,e)}_showOverlay(){document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:"div.page-wrapper"}))}_hideOverlay(){document.dispatchEvent(new Event("kimai.reloadedContent"))}_loadPage(t){this._showOverlay(),window.kimai.getPlugin("fetch").fetch(t).then((t=>{t.text().then((t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector("section.content");document.querySelector("section.content").replaceWith(n),document.dispatchEvent(new Event("kimai.reloadPage")),this._hideOverlay()}))})).catch((()=>{this._hideOverlay(),document.location=t}))}}},5247:function(t,e,n){"use strict";n.d(e,{A:function(){return i}});class i{static set(t,e){window.localStorage.setItem(t,JSON.stringify(e))}static get(t){let e=window.localStorage.getItem(t);return null==e?null:JSON.parse(e)}static remove(t){window.localStorage.removeItem(t)}}},8097:function(t,e,n){"use strict";n.d(e,{c9:function(){return bi},dw:function(){return Sn},wB:function(){return wt}});class i extends Error{}class o extends i{constructor(t){super(`Invalid DateTime: ${t.toMessage()}`)}}class r extends i{constructor(t){super(`Invalid Interval: ${t.toMessage()}`)}}class s extends i{constructor(t){super(`Invalid Duration: ${t.toMessage()}`)}}class a extends i{}class l extends i{constructor(t){super(`Invalid unit ${t}`)}}class c extends i{}class u extends i{constructor(){super("Zone is an abstract class")}}const d="numeric",h="short",p="long",m={year:d,month:d,day:d},f={year:d,month:h,day:d},g={year:d,month:h,day:d,weekday:h},v={year:d,month:p,day:d},y={year:d,month:p,day:d,weekday:p},b={hour:d,minute:d},_={hour:d,minute:d,second:d},w={hour:d,minute:d,second:d,timeZoneName:h},k={hour:d,minute:d,second:d,timeZoneName:p},E={hour:d,minute:d,hourCycle:"h23"},D={hour:d,minute:d,second:d,hourCycle:"h23"},T={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:h},S={hour:d,minute:d,second:d,hourCycle:"h23",timeZoneName:p},x={year:d,month:d,day:d,hour:d,minute:d},O={year:d,month:d,day:d,hour:d,minute:d,second:d},C={year:d,month:h,day:d,hour:d,minute:d},L={year:d,month:h,day:d,hour:d,minute:d,second:d},M={year:d,month:h,day:d,weekday:h,hour:d,minute:d},A={year:d,month:p,day:d,hour:d,minute:d,timeZoneName:h},I={year:d,month:p,day:d,hour:d,minute:d,second:d,timeZoneName:h},N={year:d,month:p,day:d,weekday:p,hour:d,minute:d,timeZoneName:p},P={year:d,month:p,day:d,weekday:p,hour:d,minute:d,second:d,timeZoneName:p};class F{get type(){throw new u}get name(){throw new u}get ianaName(){return this.name}get isUniversal(){throw new u}offsetName(t,e){throw new u}formatOffset(t,e){throw new u}offset(t){throw new u}equals(t){throw new u}get isValid(){throw new u}}let j=null;class q extends F{static get instance(){return null===j&&(j=new q),j}get type(){return"system"}get name(){return(new Intl.DateTimeFormat).resolvedOptions().timeZone}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return oe(t,e,n)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){return-new Date(t).getTimezoneOffset()}equals(t){return"system"===t.type}get isValid(){return!0}}const H=new Map;const V={year:0,month:1,day:2,era:3,hour:4,minute:5,second:6};const R=new Map;class B extends F{static create(t){let e=R.get(t);return void 0===e&&R.set(t,e=new B(t)),e}static resetCache(){R.clear(),H.clear()}static isValidSpecifier(t){return this.isValidZone(t)}static isValidZone(t){if(!t)return!1;try{return new Intl.DateTimeFormat("en-US",{timeZone:t}).format(),!0}catch(t){return!1}}constructor(t){super(),this.zoneName=t,this.valid=B.isValidZone(t)}get type(){return"iana"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(t,{format:e,locale:n}){return oe(t,e,n,this.name)}formatOffset(t,e){return le(this.offset(t),e)}offset(t){if(!this.valid)return NaN;const e=new Date(t);if(isNaN(e))return NaN;const n=function(t){let e=H.get(t);return void 0===e&&(e=new Intl.DateTimeFormat("en-US",{hour12:!1,timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",era:"short"}),H.set(t,e)),e}(this.name);let[i,o,r,s,a,l,c]=n.formatToParts?function(t,e){const n=t.formatToParts(e),i=[];for(let t=0;t=0?d:1e3+d,(te({year:i,month:o,day:r,hour:24===a?0:a,minute:l,second:c,millisecond:0})-u)/6e4}equals(t){return"iana"===t.type&&t.name===this.name}get isValid(){return this.valid}}let $={};const W=new Map;function Y(t,e={}){const n=JSON.stringify([t,e]);let i=W.get(n);return void 0===i&&(i=new Intl.DateTimeFormat(t,e),W.set(n,i)),i}const z=new Map;const U=new Map;let Z=null;const X=new Map;function K(t){let e=X.get(t);return void 0===e&&(e=new Intl.DateTimeFormat(t).resolvedOptions(),X.set(t,e)),e}const J=new Map;function G(t,e,n,i){const o=t.listingMode();return"error"===o?null:"en"===o?n(e):i(e)}class Q{constructor(t,e,n){this.padTo=n.padTo||0,this.floor=n.floor||!1;const{padTo:i,floor:o,...r}=n;if(!e||Object.keys(r).length>0){const e={useGrouping:!1,...n};n.padTo>0&&(e.minimumIntegerDigits=n.padTo),this.inf=function(t,e={}){const n=JSON.stringify([t,e]);let i=z.get(n);return void 0===i&&(i=new Intl.NumberFormat(t,e),z.set(n,i)),i}(t,e)}}format(t){if(this.inf){const e=this.floor?Math.floor(t):t;return this.inf.format(e)}return zt(this.floor?Math.floor(t):Kt(t,3),this.padTo)}}class tt{constructor(t,e,n){let i;if(this.opts=n,this.originalZone=void 0,this.opts.timeZone)this.dt=t;else if("fixed"===t.zone.type){const e=t.offset/60*-1,n=e>=0?`Etc/GMT+${e}`:`Etc/GMT${e}`;0!==t.offset&&B.create(n).valid?(i=n,this.dt=t):(i="UTC",this.dt=0===t.offset?t:t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone)}else"system"===t.zone.type?this.dt=t:"iana"===t.zone.type?(this.dt=t,i=t.zone.name):(i="UTC",this.dt=t.setZone("UTC").plus({minutes:t.offset}),this.originalZone=t.zone);const o={...this.opts};o.timeZone=o.timeZone||i,this.dtf=Y(e,o)}format(){return this.originalZone?this.formatToParts().map((({value:t})=>t)).join(""):this.dtf.format(this.dt.toJSDate())}formatToParts(){const t=this.dtf.formatToParts(this.dt.toJSDate());return this.originalZone?t.map((t=>{if("timeZoneName"===t.type){const e=this.originalZone.offsetName(this.dt.ts,{locale:this.dt.locale,format:this.opts.timeZoneName});return{...t,value:e}}return t})):t}resolvedOptions(){return this.dtf.resolvedOptions()}}class et{constructor(t,e,n){this.opts={style:"long",...n},!e&&Vt()&&(this.rtf=function(t,e={}){const{base:n,...i}=e,o=JSON.stringify([t,i]);let r=U.get(o);return void 0===r&&(r=new Intl.RelativeTimeFormat(t,e),U.set(o,r)),r}(t,n))}format(t,e){return this.rtf?this.rtf.format(t,e):function(t,e,n="always",i=!1){const o={years:["year","yr."],quarters:["quarter","qtr."],months:["month","mo."],weeks:["week","wk."],days:["day","day","days"],hours:["hour","hr."],minutes:["minute","min."],seconds:["second","sec."]},r=-1===["hours","minutes","seconds"].indexOf(t);if("auto"===n&&r){const n="days"===t;switch(e){case 1:return n?"tomorrow":`next ${o[t][0]}`;case-1:return n?"yesterday":`last ${o[t][0]}`;case 0:return n?"today":`this ${o[t][0]}`}}const s=Object.is(e,-0)||e<0,a=Math.abs(e),l=1===a,c=o[t],u=i?l?c[1]:c[2]||c[1]:l?o[t][0]:t;return s?`${a} ${u} ago`:`in ${a} ${u}`}(e,t,this.opts.numeric,"long"!==this.opts.style)}formatToParts(t,e){return this.rtf?this.rtf.formatToParts(t,e):[]}}const nt={firstDay:1,minimalDays:4,weekend:[6,7]};class it{static fromOpts(t){return it.create(t.locale,t.numberingSystem,t.outputCalendar,t.weekSettings,t.defaultToEN)}static create(t,e,n,i,o=!1){const r=t||wt.defaultLocale,s=r||(o?"en-US":Z||(Z=(new Intl.DateTimeFormat).resolvedOptions().locale,Z)),a=e||wt.defaultNumberingSystem,l=n||wt.defaultOutputCalendar,c=Wt(i)||wt.defaultWeekSettings;return new it(s,a,l,c,r)}static resetCache(){Z=null,W.clear(),z.clear(),U.clear(),X.clear(),J.clear()}static fromObject({locale:t,numberingSystem:e,outputCalendar:n,weekSettings:i}={}){return it.create(t,e,n,i)}constructor(t,e,n,i,o){const[r,s,a]=function(t){const e=t.indexOf("-x-");-1!==e&&(t=t.substring(0,e));const n=t.indexOf("-u-");if(-1===n)return[t];{let e,i;try{e=Y(t).resolvedOptions(),i=t}catch(o){const r=t.substring(0,n);e=Y(r).resolvedOptions(),i=r}const{numberingSystem:o,calendar:r}=e;return[i,o,r]}}(t);this.locale=r,this.numberingSystem=e||s||null,this.outputCalendar=n||a||null,this.weekSettings=i,this.intl=function(t,e,n){return n||e?(t.includes("-u-")||(t+="-u"),n&&(t+=`-ca-${n}`),e&&(t+=`-nu-${e}`),t):t}(this.locale,this.numberingSystem,this.outputCalendar),this.weekdaysCache={format:{},standalone:{}},this.monthsCache={format:{},standalone:{}},this.meridiemCache=null,this.eraCache={},this.specifiedLocale=o,this.fastNumbersCached=null}get fastNumbers(){var t;return null==this.fastNumbersCached&&(this.fastNumbersCached=(!(t=this).numberingSystem||"latn"===t.numberingSystem)&&("latn"===t.numberingSystem||!t.locale||t.locale.startsWith("en")||"latn"===K(t.locale).numberingSystem)),this.fastNumbersCached}listingMode(){const t=this.isEnglish(),e=!(null!==this.numberingSystem&&"latn"!==this.numberingSystem||null!==this.outputCalendar&&"gregory"!==this.outputCalendar);return t&&e?"en":"intl"}clone(t){return t&&0!==Object.getOwnPropertyNames(t).length?it.create(t.locale||this.specifiedLocale,t.numberingSystem||this.numberingSystem,t.outputCalendar||this.outputCalendar,Wt(t.weekSettings)||this.weekSettings,t.defaultToEN||!1):this}redefaultToEN(t={}){return this.clone({...t,defaultToEN:!0})}redefaultToSystem(t={}){return this.clone({...t,defaultToEN:!1})}months(t,e=!1){return G(this,t,pe,(()=>{const n="ja"===this.intl||this.intl.startsWith("ja-"),i=(e&=!n)?{month:t,day:"numeric"}:{month:t},o=e?"format":"standalone";if(!this.monthsCache[o][t]){const e=n?t=>this.dtFormatter(t,i).format():t=>this.extract(t,i,"month");this.monthsCache[o][t]=function(t){const e=[];for(let n=1;n<=12;n++){const i=bi.utc(2009,n,1);e.push(t(i))}return e}(e)}return this.monthsCache[o][t]}))}weekdays(t,e=!1){return G(this,t,ve,(()=>{const n=e?{weekday:t,year:"numeric",month:"long",day:"numeric"}:{weekday:t},i=e?"format":"standalone";return this.weekdaysCache[i][t]||(this.weekdaysCache[i][t]=function(t){const e=[];for(let n=1;n<=7;n++){const i=bi.utc(2016,11,13+n);e.push(t(i))}return e}((t=>this.extract(t,n,"weekday")))),this.weekdaysCache[i][t]}))}meridiems(){return G(this,void 0,(()=>ye),(()=>{if(!this.meridiemCache){const t={hour:"numeric",hourCycle:"h12"};this.meridiemCache=[bi.utc(2016,11,13,9),bi.utc(2016,11,13,19)].map((e=>this.extract(e,t,"dayperiod")))}return this.meridiemCache}))}eras(t){return G(this,t,ke,(()=>{const e={era:t};return this.eraCache[t]||(this.eraCache[t]=[bi.utc(-40,1,1),bi.utc(2017,1,1)].map((t=>this.extract(t,e,"era")))),this.eraCache[t]}))}extract(t,e,n){const i=this.dtFormatter(t,e).formatToParts().find((t=>t.type.toLowerCase()===n));return i?i.value:null}numberFormatter(t={}){return new Q(this.intl,t.forceSimple||this.fastNumbers,t)}dtFormatter(t,e={}){return new tt(t,this.intl,e)}relFormatter(t={}){return new et(this.intl,this.isEnglish(),t)}listFormatter(t={}){return function(t,e={}){const n=JSON.stringify([t,e]);let i=$[n];return i||(i=new Intl.ListFormat(t,e),$[n]=i),i}(this.intl,t)}isEnglish(){return"en"===this.locale||"en-us"===this.locale.toLowerCase()||K(this.intl).locale.startsWith("en-us")}getWeekSettings(){return this.weekSettings?this.weekSettings:Rt()?function(t){let e=J.get(t);if(!e){const n=new Intl.Locale(t);e="getWeekInfo"in n?n.getWeekInfo():n.weekInfo,"minimalDays"in e||(e={...nt,...e}),J.set(t,e)}return e}(this.locale):nt}getStartOfWeek(){return this.getWeekSettings().firstDay}getMinDaysInFirstWeek(){return this.getWeekSettings().minimalDays}getWeekendDays(){return this.getWeekSettings().weekend}equals(t){return this.locale===t.locale&&this.numberingSystem===t.numberingSystem&&this.outputCalendar===t.outputCalendar}toString(){return`Locale(${this.locale}, ${this.numberingSystem}, ${this.outputCalendar})`}}let ot=null;class rt extends F{static get utcInstance(){return null===ot&&(ot=new rt(0)),ot}static instance(t){return 0===t?rt.utcInstance:new rt(t)}static parseSpecifier(t){if(t){const e=t.match(/^utc(?:([+-]\d{1,2})(?::(\d{2}))?)?$/i);if(e)return new rt(re(e[1],e[2]))}return null}constructor(t){super(),this.fixed=t}get type(){return"fixed"}get name(){return 0===this.fixed?"UTC":`UTC${le(this.fixed,"narrow")}`}get ianaName(){return 0===this.fixed?"Etc/UTC":`Etc/GMT${le(-this.fixed,"narrow")}`}offsetName(){return this.name}formatOffset(t,e){return le(this.fixed,e)}get isUniversal(){return!0}offset(){return this.fixed}equals(t){return"fixed"===t.type&&t.fixed===this.fixed}get isValid(){return!0}}class st extends F{constructor(t){super(),this.zoneName=t}get type(){return"invalid"}get name(){return this.zoneName}get isUniversal(){return!1}offsetName(){return null}formatOffset(){return""}offset(){return NaN}equals(){return!1}get isValid(){return!1}}function at(t,e){if(jt(t)||null===t)return e;if(t instanceof F)return t;if("string"==typeof t){const n=t.toLowerCase();return"default"===n?e:"local"===n||"system"===n?q.instance:"utc"===n||"gmt"===n?rt.utcInstance:rt.parseSpecifier(n)||B.create(t)}return qt(t)?rt.instance(t):"object"==typeof t&&"offset"in t&&"function"==typeof t.offset?t:new st(t)}const lt={arab:"[٠-٩]",arabext:"[۰-۹]",bali:"[᭐-᭙]",beng:"[০-৯]",deva:"[०-९]",fullwide:"[0-9]",gujr:"[૦-૯]",hanidec:"[〇|一|二|三|四|五|六|七|八|九]",khmr:"[០-៩]",knda:"[೦-೯]",laoo:"[໐-໙]",limb:"[᥆-᥏]",mlym:"[൦-൯]",mong:"[᠐-᠙]",mymr:"[၀-၉]",orya:"[୦-୯]",tamldec:"[௦-௯]",telu:"[౦-౯]",thai:"[๐-๙]",tibt:"[༠-༩]",latn:"\\d"},ct={arab:[1632,1641],arabext:[1776,1785],bali:[6992,7001],beng:[2534,2543],deva:[2406,2415],fullwide:[65296,65303],gujr:[2790,2799],khmr:[6112,6121],knda:[3302,3311],laoo:[3792,3801],limb:[6470,6479],mlym:[3430,3439],mong:[6160,6169],mymr:[4160,4169],orya:[2918,2927],tamldec:[3046,3055],telu:[3174,3183],thai:[3664,3673],tibt:[3872,3881]},ut=lt.hanidec.replace(/[\[|\]]/g,"").split("");const dt=new Map;function ht({numberingSystem:t},e=""){const n=t||"latn";let i=dt.get(n);void 0===i&&(i=new Map,dt.set(n,i));let o=i.get(e);return void 0===o&&(o=new RegExp(`${lt[n]}${e}`),i.set(e,o)),o}let pt,mt=()=>Date.now(),ft="system",gt=null,vt=null,yt=null,bt=60,_t=null;class wt{static get now(){return mt}static set now(t){mt=t}static set defaultZone(t){ft=t}static get defaultZone(){return at(ft,q.instance)}static get defaultLocale(){return gt}static set defaultLocale(t){gt=t}static get defaultNumberingSystem(){return vt}static set defaultNumberingSystem(t){vt=t}static get defaultOutputCalendar(){return yt}static set defaultOutputCalendar(t){yt=t}static get defaultWeekSettings(){return _t}static set defaultWeekSettings(t){_t=Wt(t)}static get twoDigitCutoffYear(){return bt}static set twoDigitCutoffYear(t){bt=t%100}static get throwOnInvalid(){return pt}static set throwOnInvalid(t){pt=t}static resetCaches(){it.resetCache(),B.resetCache(),bi.resetCache(),dt.clear()}}class kt{constructor(t,e){this.reason=t,this.explanation=e}toMessage(){return this.explanation?`${this.reason}: ${this.explanation}`:this.reason}}const Et=[0,31,59,90,120,151,181,212,243,273,304,334],Dt=[0,31,60,91,121,152,182,213,244,274,305,335];function Tt(t,e){return new kt("unit out of range",`you specified ${e} (of type ${typeof e}) as a ${t}, which is invalid`)}function St(t,e,n){const i=new Date(Date.UTC(t,e-1,n));t<100&&t>=0&&i.setUTCFullYear(i.getUTCFullYear()-1900);const o=i.getUTCDay();return 0===o?7:o}function xt(t,e,n){return n+(Jt(t)?Dt:Et)[e-1]}function Ot(t,e){const n=Jt(t)?Dt:Et,i=n.findIndex((t=>tne(i,e,n)?(l=i+1,c=1):l=i,{weekYear:l,weekNumber:c,weekday:a,...ce(t)}}function Mt(t,e=4,n=1){const{weekYear:i,weekNumber:o,weekday:r}=t,s=Ct(St(i,1,e),n),a=Gt(i);let l,c=7*o+r-s-7+e;c<1?(l=i-1,c+=Gt(l)):c>a?(l=i+1,c-=Gt(i)):l=i;const{month:u,day:d}=Ot(l,c);return{year:l,month:u,day:d,...ce(t)}}function At(t){const{year:e,month:n,day:i}=t;return{year:e,ordinal:xt(e,n,i),...ce(t)}}function It(t){const{year:e,ordinal:n}=t,{month:i,day:o}=Ot(e,n);return{year:e,month:i,day:o,...ce(t)}}function Nt(t,e){if(!jt(t.localWeekday)||!jt(t.localWeekNumber)||!jt(t.localWeekYear)){if(!jt(t.weekday)||!jt(t.weekNumber)||!jt(t.weekYear))throw new a("Cannot mix locale-based week fields with ISO-based week fields");return jt(t.localWeekday)||(t.weekday=t.localWeekday),jt(t.localWeekNumber)||(t.weekNumber=t.localWeekNumber),jt(t.localWeekYear)||(t.weekYear=t.localWeekYear),delete t.localWeekday,delete t.localWeekNumber,delete t.localWeekYear,{minDaysInFirstWeek:e.getMinDaysInFirstWeek(),startOfWeek:e.getStartOfWeek()}}return{minDaysInFirstWeek:4,startOfWeek:1}}function Pt(t){const e=Ht(t.year),n=Yt(t.month,1,12),i=Yt(t.day,1,Qt(t.year,t.month));return e?n?!i&&Tt("day",t.day):Tt("month",t.month):Tt("year",t.year)}function Ft(t){const{hour:e,minute:n,second:i,millisecond:o}=t,r=Yt(e,0,23)||24===e&&0===n&&0===i&&0===o,s=Yt(n,0,59),a=Yt(i,0,59),l=Yt(o,0,999);return r?s?a?!l&&Tt("millisecond",o):Tt("second",i):Tt("minute",n):Tt("hour",e)}function jt(t){return void 0===t}function qt(t){return"number"==typeof t}function Ht(t){return"number"==typeof t&&t%1==0}function Vt(){try{return"undefined"!=typeof Intl&&!!Intl.RelativeTimeFormat}catch(t){return!1}}function Rt(){try{return"undefined"!=typeof Intl&&!!Intl.Locale&&("weekInfo"in Intl.Locale.prototype||"getWeekInfo"in Intl.Locale.prototype)}catch(t){return!1}}function Bt(t,e,n){if(0!==t.length)return t.reduce(((t,i)=>{const o=[e(i),i];return t&&n(t[0],o[0])===t[0]?t:o}),null)[1]}function $t(t,e){return Object.prototype.hasOwnProperty.call(t,e)}function Wt(t){if(null==t)return null;if("object"!=typeof t)throw new c("Week settings must be an object");if(!Yt(t.firstDay,1,7)||!Yt(t.minimalDays,1,7)||!Array.isArray(t.weekend)||t.weekend.some((t=>!Yt(t,1,7))))throw new c("Invalid week settings");return{firstDay:t.firstDay,minimalDays:t.minimalDays,weekend:Array.from(t.weekend)}}function Yt(t,e,n){return Ht(t)&&t>=e&&t<=n}function zt(t,e=2){let n;return n=t<0?"-"+(""+-t).padStart(e,"0"):(""+t).padStart(e,"0"),n}function Ut(t){return jt(t)||null===t||""===t?void 0:parseInt(t,10)}function Zt(t){return jt(t)||null===t||""===t?void 0:parseFloat(t)}function Xt(t){if(!jt(t)&&null!==t&&""!==t){const e=1e3*parseFloat("0."+t);return Math.floor(e)}}function Kt(t,e,n="round"){const i=10**e;switch(n){case"expand":return t>0?Math.ceil(t*i)/i:Math.floor(t*i)/i;case"trunc":return Math.trunc(t*i)/i;case"round":return Math.round(t*i)/i;case"floor":return Math.floor(t*i)/i;case"ceil":return Math.ceil(t*i)/i;default:throw new RangeError(`Value rounding ${n} is out of range`)}}function Jt(t){return t%4==0&&(t%100!=0||t%400==0)}function Gt(t){return Jt(t)?366:365}function Qt(t,e){const n=function(t,e){return t-e*Math.floor(t/e)}(e-1,12)+1;return 2===n?Jt(t+(e-n)/12)?29:28:[31,null,31,30,31,30,31,31,30,31,30,31][n-1]}function te(t){let e=Date.UTC(t.year,t.month-1,t.day,t.hour,t.minute,t.second,t.millisecond);return t.year<100&&t.year>=0&&(e=new Date(e),e.setUTCFullYear(t.year,t.month-1,t.day)),+e}function ee(t,e,n){return-Ct(St(t,1,e),n)+e-1}function ne(t,e=4,n=1){const i=ee(t,e,n),o=ee(t+1,e,n);return(Gt(t)-i+o)/7}function ie(t){return t>99?t:t>wt.twoDigitCutoffYear?1900+t:2e3+t}function oe(t,e,n,i=null){const o=new Date(t),r={hourCycle:"h23",year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit"};i&&(r.timeZone=i);const s={timeZoneName:e,...r},a=new Intl.DateTimeFormat(n,s).formatToParts(o).find((t=>"timezonename"===t.type.toLowerCase()));return a?a.value:null}function re(t,e){let n=parseInt(t,10);Number.isNaN(n)&&(n=0);const i=parseInt(e,10)||0;return 60*n+(n<0||Object.is(n,-0)?-i:i)}function se(t){const e=Number(t);if("boolean"==typeof t||""===t||!Number.isFinite(e))throw new c(`Invalid unit value ${t}`);return e}function ae(t,e){const n={};for(const i in t)if($t(t,i)){const o=t[i];if(null==o)continue;n[e(i)]=se(o)}return n}function le(t,e){const n=Math.trunc(Math.abs(t/60)),i=Math.trunc(Math.abs(t%60)),o=t>=0?"+":"-";switch(e){case"short":return`${o}${zt(n,2)}:${zt(i,2)}`;case"narrow":return`${o}${n}${i>0?`:${i}`:""}`;case"techie":return`${o}${zt(n,2)}${zt(i,2)}`;default:throw new RangeError(`Value format ${e} is out of range for property format`)}}function ce(t){return function(t,e){return e.reduce(((e,n)=>(e[n]=t[n],e)),{})}(t,["hour","minute","second","millisecond"])}const ue=["January","February","March","April","May","June","July","August","September","October","November","December"],de=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],he=["J","F","M","A","M","J","J","A","S","O","N","D"];function pe(t){switch(t){case"narrow":return[...he];case"short":return[...de];case"long":return[...ue];case"numeric":return["1","2","3","4","5","6","7","8","9","10","11","12"];case"2-digit":return["01","02","03","04","05","06","07","08","09","10","11","12"];default:return null}}const me=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],fe=["Mon","Tue","Wed","Thu","Fri","Sat","Sun"],ge=["M","T","W","T","F","S","S"];function ve(t){switch(t){case"narrow":return[...ge];case"short":return[...fe];case"long":return[...me];case"numeric":return["1","2","3","4","5","6","7"];default:return null}}const ye=["AM","PM"],be=["Before Christ","Anno Domini"],_e=["BC","AD"],we=["B","A"];function ke(t){switch(t){case"narrow":return[...we];case"short":return[..._e];case"long":return[...be];default:return null}}function Ee(t,e){let n="";for(const i of t)i.literal?n+=i.val:n+=e(i.val);return n}const De={D:m,DD:f,DDD:v,DDDD:y,t:b,tt:_,ttt:w,tttt:k,T:E,TT:D,TTT:T,TTTT:S,f:x,ff:C,fff:A,ffff:N,F:O,FF:L,FFF:I,FFFF:P};class Te{static create(t,e={}){return new Te(t,e)}static parseFormat(t){let e=null,n="",i=!1;const o=[];for(let r=0;r0||i)&&o.push({literal:i||/^\s+$/.test(n),val:""===n?"'":n}),e=null,n="",i=!i):i||s===e?n+=s:(n.length>0&&o.push({literal:/^\s+$/.test(n),val:n}),n=s,e=s)}return n.length>0&&o.push({literal:i||/^\s+$/.test(n),val:n}),o}static macroTokenToFormatOpts(t){return De[t]}constructor(t,e){this.opts=e,this.loc=t,this.systemLoc=null}formatWithSystemDefault(t,e){null===this.systemLoc&&(this.systemLoc=this.loc.redefaultToSystem());return this.systemLoc.dtFormatter(t,{...this.opts,...e}).format()}dtFormatter(t,e={}){return this.loc.dtFormatter(t,{...this.opts,...e})}formatDateTime(t,e){return this.dtFormatter(t,e).format()}formatDateTimeParts(t,e){return this.dtFormatter(t,e).formatToParts()}formatInterval(t,e){return this.dtFormatter(t.start,e).dtf.formatRange(t.start.toJSDate(),t.end.toJSDate())}resolvedOptions(t,e){return this.dtFormatter(t,e).resolvedOptions()}num(t,e=0,n){if(this.opts.forceSimple)return zt(t,e);const i={...this.opts};return e>0&&(i.padTo=e),n&&(i.signDisplay=n),this.loc.numberFormatter(i).format(t)}formatDateTimeFromString(t,e){const n="en"===this.loc.listingMode(),i=this.loc.outputCalendar&&"gregory"!==this.loc.outputCalendar,o=(e,n)=>this.loc.extract(t,e,n),r=e=>t.isOffsetFixed&&0===t.offset&&e.allowZ?"Z":t.isValid?t.zone.formatOffset(t.ts,e.format):"",s=()=>n?function(t){return ye[t.hour<12?0:1]}(t):o({hour:"numeric",hourCycle:"h12"},"dayperiod"),a=(e,i)=>n?function(t,e){return pe(e)[t.month-1]}(t,e):o(i?{month:e}:{month:e,day:"numeric"},"month"),l=(e,i)=>n?function(t,e){return ve(e)[t.weekday-1]}(t,e):o(i?{weekday:e}:{weekday:e,month:"long",day:"numeric"},"weekday"),c=e=>{const n=Te.macroTokenToFormatOpts(e);return n?this.formatWithSystemDefault(t,n):e},u=e=>n?function(t,e){return ke(e)[t.year<0?0:1]}(t,e):o({era:e},"era");return Ee(Te.parseFormat(e),(e=>{switch(e){case"S":return this.num(t.millisecond);case"u":case"SSS":return this.num(t.millisecond,3);case"s":return this.num(t.second);case"ss":return this.num(t.second,2);case"uu":return this.num(Math.floor(t.millisecond/10),2);case"uuu":return this.num(Math.floor(t.millisecond/100));case"m":return this.num(t.minute);case"mm":return this.num(t.minute,2);case"h":return this.num(t.hour%12==0?12:t.hour%12);case"hh":return this.num(t.hour%12==0?12:t.hour%12,2);case"H":return this.num(t.hour);case"HH":return this.num(t.hour,2);case"Z":return r({format:"narrow",allowZ:this.opts.allowZ});case"ZZ":return r({format:"short",allowZ:this.opts.allowZ});case"ZZZ":return r({format:"techie",allowZ:this.opts.allowZ});case"ZZZZ":return t.zone.offsetName(t.ts,{format:"short",locale:this.loc.locale});case"ZZZZZ":return t.zone.offsetName(t.ts,{format:"long",locale:this.loc.locale});case"z":return t.zoneName;case"a":return s();case"d":return i?o({day:"numeric"},"day"):this.num(t.day);case"dd":return i?o({day:"2-digit"},"day"):this.num(t.day,2);case"c":case"E":return this.num(t.weekday);case"ccc":return l("short",!0);case"cccc":return l("long",!0);case"ccccc":return l("narrow",!0);case"EEE":return l("short",!1);case"EEEE":return l("long",!1);case"EEEEE":return l("narrow",!1);case"L":return i?o({month:"numeric",day:"numeric"},"month"):this.num(t.month);case"LL":return i?o({month:"2-digit",day:"numeric"},"month"):this.num(t.month,2);case"LLL":return a("short",!0);case"LLLL":return a("long",!0);case"LLLLL":return a("narrow",!0);case"M":return i?o({month:"numeric"},"month"):this.num(t.month);case"MM":return i?o({month:"2-digit"},"month"):this.num(t.month,2);case"MMM":return a("short",!1);case"MMMM":return a("long",!1);case"MMMMM":return a("narrow",!1);case"y":return i?o({year:"numeric"},"year"):this.num(t.year);case"yy":return i?o({year:"2-digit"},"year"):this.num(t.year.toString().slice(-2),2);case"yyyy":return i?o({year:"numeric"},"year"):this.num(t.year,4);case"yyyyyy":return i?o({year:"numeric"},"year"):this.num(t.year,6);case"G":return u("short");case"GG":return u("long");case"GGGGG":return u("narrow");case"kk":return this.num(t.weekYear.toString().slice(-2),2);case"kkkk":return this.num(t.weekYear,4);case"W":return this.num(t.weekNumber);case"WW":return this.num(t.weekNumber,2);case"n":return this.num(t.localWeekNumber);case"nn":return this.num(t.localWeekNumber,2);case"ii":return this.num(t.localWeekYear.toString().slice(-2),2);case"iiii":return this.num(t.localWeekYear,4);case"o":return this.num(t.ordinal);case"ooo":return this.num(t.ordinal,3);case"q":return this.num(t.quarter);case"qq":return this.num(t.quarter,2);case"X":return this.num(Math.floor(t.ts/1e3));case"x":return this.num(t.ts);default:return c(e)}}))}formatDurationFromString(t,e){const n="negativeLargestOnly"===this.opts.signMode?-1:1,i=t=>{switch(t[0]){case"S":return"milliseconds";case"s":return"seconds";case"m":return"minutes";case"h":return"hours";case"d":return"days";case"w":return"weeks";case"M":return"months";case"y":return"years";default:return null}},o=Te.parseFormat(e),r=o.reduce(((t,{literal:e,val:n})=>e?t:t.concat(n)),[]),s=t.shiftTo(...r.map(i).filter((t=>t)));return Ee(o,((t,e)=>o=>{const r=i(o);if(r){const i=e.isNegativeDuration&&r!==e.largestUnit?n:1;let s;return s="negativeLargestOnly"===this.opts.signMode&&r!==e.largestUnit?"never":"all"===this.opts.signMode?"always":"auto",this.num(t.get(r)*i,o.length,s)}return o})(s,{isNegativeDuration:s<0,largestUnit:Object.keys(s.values)[0]}))}}const Se=/[A-Za-z_+-]{1,256}(?::?\/[A-Za-z0-9_+-]{1,256}(?:\/[A-Za-z0-9_+-]{1,256})?)?/;function xe(...t){const e=t.reduce(((t,e)=>t+e.source),"");return RegExp(`^${e}$`)}function Oe(...t){return e=>t.reduce((([t,n,i],o)=>{const[r,s,a]=o(e,i);return[{...t,...r},s||n,a]}),[{},null,1]).slice(0,2)}function Ce(t,...e){if(null==t)return[null,null];for(const[n,i]of e){const e=n.exec(t);if(e)return i(e)}return[null,null]}function Le(...t){return(e,n)=>{const i={};let o;for(o=0;ovoid 0!==t&&(e||t&&u)?-t:t;return[{years:h(Zt(n)),months:h(Zt(i)),weeks:h(Zt(o)),days:h(Zt(r)),hours:h(Zt(s)),minutes:h(Zt(a)),seconds:h(Zt(l),"-0"===l),milliseconds:h(Xt(c),d)}]}const ze={GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ue(t,e,n,i,o,r,s){const a={year:2===e.length?ie(Ut(e)):Ut(e),month:de.indexOf(n)+1,day:Ut(i),hour:Ut(o),minute:Ut(r)};return s&&(a.second=Ut(s)),t&&(a.weekday=t.length>3?me.indexOf(t)+1:fe.indexOf(t)+1),a}const Ze=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|(?:([+-]\d\d)(\d\d)))$/;function Xe(t){const[,e,n,i,o,r,s,a,l,c,u,d]=t,h=Ue(e,o,i,n,r,s,a);let p;return p=l?ze[l]:c?0:re(u,d),[h,new rt(p)]}const Ke=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), (\d\d) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) (\d{4}) (\d\d):(\d\d):(\d\d) GMT$/,Je=/^(Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday), (\d\d)-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(\d\d) (\d\d):(\d\d):(\d\d) GMT$/,Ge=/^(Mon|Tue|Wed|Thu|Fri|Sat|Sun) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ( \d|\d\d) (\d\d):(\d\d):(\d\d) (\d{4})$/;function Qe(t){const[,e,n,i,o,r,s,a]=t;return[Ue(e,o,i,n,r,s,a),rt.utcInstance]}function tn(t){const[,e,n,i,o,r,s,a]=t;return[Ue(e,a,n,i,o,r,s),rt.utcInstance]}const en=xe(/([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/,Ne),nn=xe(/(\d{4})-?W(\d\d)(?:-?(\d))?/,Ne),on=xe(/(\d{4})-?(\d{3})/,Ne),rn=xe(Ie),sn=Oe((function(t,e){return[{year:He(t,e),month:He(t,e+1,1),day:He(t,e+2,1)},null,e+3]}),Ve,Re,Be),an=Oe(Pe,Ve,Re,Be),ln=Oe(Fe,Ve,Re,Be),cn=Oe(Ve,Re,Be);const un=Oe(Ve);const dn=xe(/(\d{4})-(\d\d)-(\d\d)/,qe),hn=xe(je),pn=Oe(Ve,Re,Be);const mn="Invalid Duration",fn={weeks:{days:7,hours:168,minutes:10080,seconds:604800,milliseconds:6048e5},days:{hours:24,minutes:1440,seconds:86400,milliseconds:864e5},hours:{minutes:60,seconds:3600,milliseconds:36e5},minutes:{seconds:60,milliseconds:6e4},seconds:{milliseconds:1e3}},gn={years:{quarters:4,months:12,weeks:52,days:365,hours:8760,minutes:525600,seconds:31536e3,milliseconds:31536e6},quarters:{months:3,weeks:13,days:91,hours:2184,minutes:131040,seconds:7862400,milliseconds:78624e5},months:{weeks:4,days:30,hours:720,minutes:43200,seconds:2592e3,milliseconds:2592e6},...fn},vn=365.2425,yn=30.436875,bn={years:{quarters:4,months:12,weeks:52.1775,days:vn,hours:8765.82,minutes:525949.2,seconds:525949.2*60,milliseconds:525949.2*60*1e3},quarters:{months:3,weeks:13.044375,days:91.310625,hours:2191.455,minutes:131487.3,seconds:525949.2*60/4,milliseconds:7889237999.999999},months:{weeks:4.3481250000000005,days:yn,hours:730.485,minutes:43829.1,seconds:2629746,milliseconds:2629746e3},...fn},_n=["years","quarters","months","weeks","days","hours","minutes","seconds","milliseconds"],wn=_n.slice(0).reverse();function kn(t,e,n=!1){const i={values:n?e.values:{...t.values,...e.values||{}},loc:t.loc.clone(e.loc),conversionAccuracy:e.conversionAccuracy||t.conversionAccuracy,matrix:e.matrix||t.matrix};return new Sn(i)}function En(t,e){let n=e.milliseconds??0;for(const i of wn.slice(1))e[i]&&(n+=e[i]*t[i].milliseconds);return n}function Dn(t,e){const n=En(t,e)<0?-1:1;_n.reduceRight(((i,o)=>{if(jt(e[o]))return i;if(i){const r=e[i]*n,s=t[o][i],a=Math.floor(r/s);e[o]+=a*n,e[i]-=a*s*n}return o}),null),_n.reduce(((n,i)=>{if(jt(e[i]))return n;if(n){const o=e[n]%1;e[n]-=o,e[i]+=o*t[n][i]}return i}),null)}function Tn(t){const e={};for(const[n,i]of Object.entries(t))0!==i&&(e[n]=i);return e}class Sn{constructor(t){const e="longterm"===t.conversionAccuracy||!1;let n=e?bn:gn;t.matrix&&(n=t.matrix),this.values=t.values,this.loc=t.loc||it.create(),this.conversionAccuracy=e?"longterm":"casual",this.invalid=t.invalid||null,this.matrix=n,this.isLuxonDuration=!0}static fromMillis(t,e){return Sn.fromObject({milliseconds:t},e)}static fromObject(t,e={}){if(null==t||"object"!=typeof t)throw new c("Duration.fromObject: argument expected to be an object, got "+(null===t?"null":typeof t));return new Sn({values:ae(t,Sn.normalizeUnit),loc:it.fromObject(e),conversionAccuracy:e.conversionAccuracy,matrix:e.matrix})}static fromDurationLike(t){if(qt(t))return Sn.fromMillis(t);if(Sn.isDuration(t))return t;if("object"==typeof t)return Sn.fromObject(t);throw new c(`Unknown duration argument ${t} of type ${typeof t}`)}static fromISO(t,e){const[n]=function(t){return Ce(t,[We,Ye])}(t);return n?Sn.fromObject(n,e):Sn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static fromISOTime(t,e){const[n]=function(t){return Ce(t,[$e,un])}(t);return n?Sn.fromObject(n,e):Sn.invalid("unparsable",`the input "${t}" can't be parsed as ISO 8601`)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Duration is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new s(n);return new Sn({invalid:n})}static normalizeUnit(t){const e={year:"years",years:"years",quarter:"quarters",quarters:"quarters",month:"months",months:"months",week:"weeks",weeks:"weeks",day:"days",days:"days",hour:"hours",hours:"hours",minute:"minutes",minutes:"minutes",second:"seconds",seconds:"seconds",millisecond:"milliseconds",milliseconds:"milliseconds"}[t?t.toLowerCase():t];if(!e)throw new l(t);return e}static isDuration(t){return t&&t.isLuxonDuration||!1}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}toFormat(t,e={}){const n={...e,floor:!1!==e.round&&!1!==e.floor};return this.isValid?Te.create(this.loc,n).formatDurationFromString(this,t):mn}toHuman(t={}){if(!this.isValid)return mn;const e=!1!==t.showZeros,n=_n.map((n=>{const i=this.values[n];return jt(i)||0===i&&!e?null:this.loc.numberFormatter({style:"unit",unitDisplay:"long",...t,unit:n.slice(0,-1)}).format(i)})).filter((t=>t));return this.loc.listFormatter({type:"conjunction",style:t.listStyle||"narrow",...t}).format(n)}toObject(){return this.isValid?{...this.values}:{}}toISO(){if(!this.isValid)return null;let t="P";return 0!==this.years&&(t+=this.years+"Y"),0===this.months&&0===this.quarters||(t+=this.months+3*this.quarters+"M"),0!==this.weeks&&(t+=this.weeks+"W"),0!==this.days&&(t+=this.days+"D"),0===this.hours&&0===this.minutes&&0===this.seconds&&0===this.milliseconds||(t+="T"),0!==this.hours&&(t+=this.hours+"H"),0!==this.minutes&&(t+=this.minutes+"M"),0===this.seconds&&0===this.milliseconds||(t+=Kt(this.seconds+this.milliseconds/1e3,3)+"S"),"P"===t&&(t+="T0S"),t}toISOTime(t={}){if(!this.isValid)return null;const e=this.toMillis();if(e<0||e>=864e5)return null;t={suppressMilliseconds:!1,suppressSeconds:!1,includePrefix:!1,format:"extended",...t,includeOffset:!1};return bi.fromMillis(e,{zone:"UTC"}).toISOTime(t)}toJSON(){return this.toISO()}toString(){return this.toISO()}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Duration { values: ${JSON.stringify(this.values)} }`:`Duration { Invalid, reason: ${this.invalidReason} }`}toMillis(){return this.isValid?En(this.matrix,this.values):NaN}valueOf(){return this.toMillis()}plus(t){if(!this.isValid)return this;const e=Sn.fromDurationLike(t),n={};for(const t of _n)($t(e.values,t)||$t(this.values,t))&&(n[t]=e.get(t)+this.get(t));return kn(this,{values:n},!0)}minus(t){if(!this.isValid)return this;const e=Sn.fromDurationLike(t);return this.plus(e.negate())}mapUnits(t){if(!this.isValid)return this;const e={};for(const n of Object.keys(this.values))e[n]=se(t(this.values[n],n));return kn(this,{values:e},!0)}get(t){return this[Sn.normalizeUnit(t)]}set(t){if(!this.isValid)return this;return kn(this,{values:{...this.values,...ae(t,Sn.normalizeUnit)}})}reconfigure({locale:t,numberingSystem:e,conversionAccuracy:n,matrix:i}={}){return kn(this,{loc:this.loc.clone({locale:t,numberingSystem:e}),matrix:i,conversionAccuracy:n})}as(t){return this.isValid?this.shiftTo(t).get(t):NaN}normalize(){if(!this.isValid)return this;const t=this.toObject();return Dn(this.matrix,t),kn(this,{values:t},!0)}rescale(){if(!this.isValid)return this;return kn(this,{values:Tn(this.normalize().shiftToAll().toObject())},!0)}shiftTo(...t){if(!this.isValid)return this;if(0===t.length)return this;t=t.map((t=>Sn.normalizeUnit(t)));const e={},n={},i=this.toObject();let o;for(const r of _n)if(t.indexOf(r)>=0){o=r;let t=0;for(const e in n)t+=this.matrix[e][r]*n[e],n[e]=0;qt(i[r])&&(t+=i[r]);const s=Math.trunc(t);e[r]=s,n[r]=(1e3*t-1e3*s)/1e3}else qt(i[r])&&(n[r]=i[r]);for(const t in n)0!==n[t]&&(e[o]+=t===o?n[t]:n[t]/this.matrix[o][t]);return Dn(this.matrix,e),kn(this,{values:e},!0)}shiftToAll(){return this.isValid?this.shiftTo("years","months","weeks","days","hours","minutes","seconds","milliseconds"):this}negate(){if(!this.isValid)return this;const t={};for(const e of Object.keys(this.values))t[e]=0===this.values[e]?0:-this.values[e];return kn(this,{values:t},!0)}removeZeros(){if(!this.isValid)return this;return kn(this,{values:Tn(this.values)},!0)}get years(){return this.isValid?this.values.years||0:NaN}get quarters(){return this.isValid?this.values.quarters||0:NaN}get months(){return this.isValid?this.values.months||0:NaN}get weeks(){return this.isValid?this.values.weeks||0:NaN}get days(){return this.isValid?this.values.days||0:NaN}get hours(){return this.isValid?this.values.hours||0:NaN}get minutes(){return this.isValid?this.values.minutes||0:NaN}get seconds(){return this.isValid?this.values.seconds||0:NaN}get milliseconds(){return this.isValid?this.values.milliseconds||0:NaN}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}equals(t){if(!this.isValid||!t.isValid)return!1;if(!this.loc.equals(t.loc))return!1;for(const i of _n)if(e=this.values[i],n=t.values[i],!(void 0===e||0===e?void 0===n||0===n:e===n))return!1;var e,n;return!0}}const xn="Invalid Interval";class On{constructor(t){this.s=t.start,this.e=t.end,this.invalid=t.invalid||null,this.isLuxonInterval=!0}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the Interval is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new r(n);return new On({invalid:n})}static fromDateTimes(t,e){const n=_i(t),i=_i(e),o=function(t,e){return t&&t.isValid?e&&e.isValid?et}isBefore(t){return!!this.isValid&&this.e<=t}contains(t){return!!this.isValid&&(this.s<=t&&this.e>t)}set({start:t,end:e}={}){return this.isValid?On.fromDateTimes(t||this.s,e||this.e):this}splitAt(...t){if(!this.isValid)return[];const e=t.map(_i).filter((t=>this.contains(t))).sort(((t,e)=>t.toMillis()-e.toMillis())),n=[];let{s:i}=this,o=0;for(;i+this.e?this.e:t;n.push(On.fromDateTimes(i,r)),i=r,o+=1}return n}splitBy(t){const e=Sn.fromDurationLike(t);if(!this.isValid||!e.isValid||0===e.as("milliseconds"))return[];let n,{s:i}=this,o=1;const r=[];for(;it*o)));n=+t>+this.e?this.e:t,r.push(On.fromDateTimes(i,n)),i=n,o+=1}return r}divideEqually(t){return this.isValid?this.splitBy(this.length()/t).slice(0,t):[]}overlaps(t){return this.e>t.s&&this.s=t.e)}equals(t){return!(!this.isValid||!t.isValid)&&(this.s.equals(t.s)&&this.e.equals(t.e))}intersection(t){if(!this.isValid)return this;const e=this.s>t.s?this.s:t.s,n=this.e=n?null:On.fromDateTimes(e,n)}union(t){if(!this.isValid)return this;const e=this.st.e?this.e:t.e;return On.fromDateTimes(e,n)}static merge(t){const[e,n]=t.sort(((t,e)=>t.s-e.s)).reduce((([t,e],n)=>e?e.overlaps(n)||e.abutsStart(n)?[t,e.union(n)]:[t.concat([e]),n]:[t,n]),[[],null]);return n&&e.push(n),e}static xor(t){let e=null,n=0;const i=[],o=t.map((t=>[{time:t.s,type:"s"},{time:t.e,type:"e"}])),r=Array.prototype.concat(...o).sort(((t,e)=>t.time-e.time));for(const t of r)n+="s"===t.type?1:-1,1===n?e=t.time:(e&&+e!=+t.time&&i.push(On.fromDateTimes(e,t.time)),e=null);return On.merge(i)}difference(...t){return On.xor([this].concat(t)).map((t=>this.intersection(t))).filter((t=>t&&!t.isEmpty()))}toString(){return this.isValid?`[${this.s.toISO()} – ${this.e.toISO()})`:xn}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`Interval { start: ${this.s.toISO()}, end: ${this.e.toISO()} }`:`Interval { Invalid, reason: ${this.invalidReason} }`}toLocaleString(t=m,e={}){return this.isValid?Te.create(this.s.loc.clone(e),t).formatInterval(this):xn}toISO(t){return this.isValid?`${this.s.toISO(t)}/${this.e.toISO(t)}`:xn}toISODate(){return this.isValid?`${this.s.toISODate()}/${this.e.toISODate()}`:xn}toISOTime(t){return this.isValid?`${this.s.toISOTime(t)}/${this.e.toISOTime(t)}`:xn}toFormat(t,{separator:e=" – "}={}){return this.isValid?`${this.s.toFormat(t)}${e}${this.e.toFormat(t)}`:xn}toDuration(t,e){return this.isValid?this.e.diff(this.s,t,e):Sn.invalid(this.invalidReason)}mapEndpoints(t){return On.fromDateTimes(t(this.s),t(this.e))}}class Cn{static hasDST(t=wt.defaultZone){const e=bi.now().setZone(t).set({month:12});return!t.isUniversal&&e.offset!==e.set({month:6}).offset}static isValidIANAZone(t){return B.isValidZone(t)}static normalizeZone(t){return at(t,wt.defaultZone)}static getStartOfWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getStartOfWeek()}static getMinimumDaysInFirstWeek({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getMinDaysInFirstWeek()}static getWeekendWeekdays({locale:t=null,locObj:e=null}={}){return(e||it.create(t)).getWeekendDays().slice()}static months(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:o="gregory"}={}){return(i||it.create(e,n,o)).months(t)}static monthsFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null,outputCalendar:o="gregory"}={}){return(i||it.create(e,n,o)).months(t,!0)}static weekdays(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t)}static weekdaysFormat(t="long",{locale:e=null,numberingSystem:n=null,locObj:i=null}={}){return(i||it.create(e,n,null)).weekdays(t,!0)}static meridiems({locale:t=null}={}){return it.create(t).meridiems()}static eras(t="short",{locale:e=null}={}){return it.create(e,null,"gregory").eras(t)}static features(){return{relative:Vt(),localeWeek:Rt()}}}function Ln(t,e){const n=t=>t.toUTC(0,{keepLocalTime:!0}).startOf("day").valueOf(),i=n(e)-n(t);return Math.floor(Sn.fromMillis(i).as("days"))}function Mn(t,e,n,i){let[o,r,s,a]=function(t,e,n){const i=[["years",(t,e)=>e.year-t.year],["quarters",(t,e)=>e.quarter-t.quarter+4*(e.year-t.year)],["months",(t,e)=>e.month-t.month+12*(e.year-t.year)],["weeks",(t,e)=>{const n=Ln(t,e);return(n-n%7)/7}],["days",Ln]],o={},r=t;let s,a;for(const[l,c]of i)n.indexOf(l)>=0&&(s=l,o[l]=c(t,e),a=r.plus(o),a>e?(o[l]--,(t=r.plus(o))>e&&(a=t,o[l]--,t=r.plus(o))):t=a);return[t,o,a,s]}(t,e,n);const l=e-o,c=n.filter((t=>["hours","minutes","seconds","milliseconds"].indexOf(t)>=0));0===c.length&&(s0?Sn.fromMillis(l,i).shiftTo(...c).plus(u):u}function An(t,e=(t=>t)){return{regex:t,deser:([t])=>e(function(t){let e=parseInt(t,10);if(isNaN(e)){e="";for(let n=0;n=n&&i<=o&&(e+=i-n)}}return parseInt(e,10)}return e}(t))}}const In=`[ ${String.fromCharCode(160)}]`,Nn=new RegExp(In,"g");function Pn(t){return t.replace(/\./g,"\\.?").replace(Nn,In)}function Fn(t){return t.replace(/\./g,"").replace(Nn," ").toLowerCase()}function jn(t,e){return null===t?null:{regex:RegExp(t.map(Pn).join("|")),deser:([n])=>t.findIndex((t=>Fn(n)===Fn(t)))+e}}function qn(t,e){return{regex:t,deser:([,t,e])=>re(t,e),groups:e}}function Hn(t){return{regex:t,deser:([t])=>t}}const Vn={year:{"2-digit":"yy",numeric:"yyyyy"},month:{numeric:"M","2-digit":"MM",short:"MMM",long:"MMMM"},day:{numeric:"d","2-digit":"dd"},weekday:{short:"EEE",long:"EEEE"},dayperiod:"a",dayPeriod:"a",hour12:{numeric:"h","2-digit":"hh"},hour24:{numeric:"H","2-digit":"HH"},minute:{numeric:"m","2-digit":"mm"},second:{numeric:"s","2-digit":"ss"},timeZoneName:{long:"ZZZZZ",short:"ZZZ"}};let Rn=null;function Bn(t,e){return Array.prototype.concat(...t.map((t=>function(t,e){if(t.literal)return t;const n=Yn(Te.macroTokenToFormatOpts(t.val),e);return null==n||n.includes(void 0)?t:n}(t,e))))}class $n{constructor(t,e){if(this.locale=t,this.format=e,this.tokens=Bn(Te.parseFormat(e),t),this.units=this.tokens.map((e=>function(t,e){const n=ht(e),i=ht(e,"{2}"),o=ht(e,"{3}"),r=ht(e,"{4}"),s=ht(e,"{6}"),a=ht(e,"{1,2}"),l=ht(e,"{1,3}"),c=ht(e,"{1,6}"),u=ht(e,"{1,9}"),d=ht(e,"{2,4}"),h=ht(e,"{4,6}"),p=t=>{return{regex:RegExp((e=t.val,e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&"))),deser:([t])=>t,literal:!0};var e},m=(m=>{if(t.literal)return p(m);switch(m.val){case"G":return jn(e.eras("short"),0);case"GG":return jn(e.eras("long"),0);case"y":return An(c);case"yy":case"kk":return An(d,ie);case"yyyy":case"kkkk":return An(r);case"yyyyy":return An(h);case"yyyyyy":return An(s);case"M":case"L":case"d":case"H":case"h":case"m":case"q":case"s":case"W":return An(a);case"MM":case"LL":case"dd":case"HH":case"hh":case"mm":case"qq":case"ss":case"WW":return An(i);case"MMM":return jn(e.months("short",!0),1);case"MMMM":return jn(e.months("long",!0),1);case"LLL":return jn(e.months("short",!1),1);case"LLLL":return jn(e.months("long",!1),1);case"o":case"S":return An(l);case"ooo":case"SSS":return An(o);case"u":return Hn(u);case"uu":return Hn(a);case"uuu":case"E":case"c":return An(n);case"a":return jn(e.meridiems(),0);case"EEE":return jn(e.weekdays("short",!1),1);case"EEEE":return jn(e.weekdays("long",!1),1);case"ccc":return jn(e.weekdays("short",!0),1);case"cccc":return jn(e.weekdays("long",!0),1);case"Z":case"ZZ":return qn(new RegExp(`([+-]${a.source})(?::(${i.source}))?`),2);case"ZZZ":return qn(new RegExp(`([+-]${a.source})(${i.source})?`),2);case"z":return Hn(/[a-z_+-/]{1,256}?/i);case" ":return Hn(/[^\S\n\r]/);default:return p(m)}})(t)||{invalidReason:"missing Intl.DateTimeFormat.formatToParts support"};return m.token=t,m}(e,t))),this.disqualifyingUnit=this.units.find((t=>t.invalidReason)),!this.disqualifyingUnit){const[t,e]=[`^${(n=this.units).map((t=>t.regex)).reduce(((t,e)=>`${t}(${e.source})`),"")}$`,n];this.regex=RegExp(t,"i"),this.handlers=e}var n}explainFromTokens(t){if(this.isValid){const[e,n]=function(t,e,n){const i=t.match(e);if(i){const t={};let e=1;for(const o in n)if($t(n,o)){const r=n[o],s=r.groups?r.groups+1:1;!r.literal&&r.token&&(t[r.token.val[0]]=r.deser(i.slice(e,e+s))),e+=s}return[i,t]}return[i,{}]}(t,this.regex,this.handlers),[i,o,r]=n?function(t){let e,n=null;return jt(t.z)||(n=B.create(t.z)),jt(t.Z)||(n||(n=new rt(t.Z)),e=t.Z),jt(t.q)||(t.M=3*(t.q-1)+1),jt(t.h)||(t.h<12&&1===t.a?t.h+=12:12===t.h&&0===t.a&&(t.h=0)),0===t.G&&t.y&&(t.y=-t.y),jt(t.u)||(t.S=Xt(t.u)),[Object.keys(t).reduce(((e,n)=>{const i=(t=>{switch(t){case"S":return"millisecond";case"s":return"second";case"m":return"minute";case"h":case"H":return"hour";case"d":return"day";case"o":return"ordinal";case"L":case"M":return"month";case"y":return"year";case"E":case"c":return"weekday";case"W":return"weekNumber";case"k":return"weekYear";case"q":return"quarter";default:return null}})(n);return i&&(e[i]=t[n]),e}),{}),n,e]}(n):[null,null,void 0];if($t(n,"a")&&$t(n,"H"))throw new a("Can't include meridiem when specifying 24-hour format");return{input:t,tokens:this.tokens,regex:this.regex,rawMatches:e,matches:n,result:i,zone:o,specificOffset:r}}return{input:t,tokens:this.tokens,invalidReason:this.invalidReason}}get isValid(){return!this.disqualifyingUnit}get invalidReason(){return this.disqualifyingUnit?this.disqualifyingUnit.invalidReason:null}}function Wn(t,e,n){return new $n(t,n).explainFromTokens(e)}function Yn(t,e){if(!t)return null;const n=Te.create(e,t).dtFormatter((Rn||(Rn=bi.fromMillis(1555555555555)),Rn)),i=n.formatToParts(),o=n.resolvedOptions();return i.map((e=>function(t,e,n){const{type:i,value:o}=t;if("literal"===i){const t=/^\s+$/.test(o);return{literal:!t,val:t?" ":o}}const r=e[i];let s=i;"hour"===i&&(s=null!=e.hour12?e.hour12?"hour12":"hour24":null!=e.hourCycle?"h11"===e.hourCycle||"h12"===e.hourCycle?"hour12":"hour24":n.hour12?"hour12":"hour24");let a=Vn[s];if("object"==typeof a&&(a=a[r]),a)return{literal:!1,val:a}}(e,t,o)))}const zn="Invalid DateTime",Un=864e13;function Zn(t){return new kt("unsupported zone",`the zone "${t.name}" is not supported`)}function Xn(t){return null===t.weekData&&(t.weekData=Lt(t.c)),t.weekData}function Kn(t){return null===t.localWeekData&&(t.localWeekData=Lt(t.c,t.loc.getMinDaysInFirstWeek(),t.loc.getStartOfWeek())),t.localWeekData}function Jn(t,e){const n={ts:t.ts,zone:t.zone,c:t.c,o:t.o,loc:t.loc,invalid:t.invalid};return new bi({...n,...e,old:n})}function Gn(t,e,n){let i=t-60*e*1e3;const o=n.offset(i);if(e===o)return[i,e];i-=60*(o-e)*1e3;const r=n.offset(i);return o===r?[i,o]:[t-60*Math.min(o,r)*1e3,Math.max(o,r)]}function Qn(t,e){const n=new Date(t+=60*e*1e3);return{year:n.getUTCFullYear(),month:n.getUTCMonth()+1,day:n.getUTCDate(),hour:n.getUTCHours(),minute:n.getUTCMinutes(),second:n.getUTCSeconds(),millisecond:n.getUTCMilliseconds()}}function ti(t,e,n){return Gn(te(t),e,n)}function ei(t,e){const n=t.o,i=t.c.year+Math.trunc(e.years),o=t.c.month+Math.trunc(e.months)+3*Math.trunc(e.quarters),r={...t.c,year:i,month:o,day:Math.min(t.c.day,Qt(i,o))+Math.trunc(e.days)+7*Math.trunc(e.weeks)},s=Sn.fromObject({years:e.years-Math.trunc(e.years),quarters:e.quarters-Math.trunc(e.quarters),months:e.months-Math.trunc(e.months),weeks:e.weeks-Math.trunc(e.weeks),days:e.days-Math.trunc(e.days),hours:e.hours,minutes:e.minutes,seconds:e.seconds,milliseconds:e.milliseconds}).as("milliseconds"),a=te(r);let[l,c]=Gn(a,n,t.zone);return 0!==s&&(l+=s,c=t.zone.offset(l)),{ts:l,o:c}}function ni(t,e,n,i,o,r){const{setZone:s,zone:a}=n;if(t&&0!==Object.keys(t).length||e){const i=e||a,o=bi.fromObject(t,{...n,zone:i,specificOffset:r});return s?o:o.setZone(a)}return bi.invalid(new kt("unparsable",`the input "${o}" can't be parsed as ${i}`))}function ii(t,e,n=!0){return t.isValid?Te.create(it.create("en-US"),{allowZ:n,forceSimple:!0}).formatDateTimeFromString(t,e):null}function oi(t,e,n){const i=t.c.year>9999||t.c.year<0;let o="";if(i&&t.c.year>=0&&(o+="+"),o+=zt(t.c.year,i?6:4),"year"===n)return o;if(e){if(o+="-",o+=zt(t.c.month),"month"===n)return o;o+="-"}else if(o+=zt(t.c.month),"month"===n)return o;return o+=zt(t.c.day),o}function ri(t,e,n,i,o,r,s){let a=!n||0!==t.c.millisecond||0!==t.c.second,l="";switch(s){case"day":case"month":case"year":break;default:if(l+=zt(t.c.hour),"hour"===s)break;if(e){if(l+=":",l+=zt(t.c.minute),"minute"===s)break;a&&(l+=":",l+=zt(t.c.second))}else{if(l+=zt(t.c.minute),"minute"===s)break;a&&(l+=zt(t.c.second))}if("second"===s)break;!a||i&&0===t.c.millisecond||(l+=".",l+=zt(t.c.millisecond,3))}return o&&(t.isOffsetFixed&&0===t.offset&&!r?l+="Z":t.o<0?(l+="-",l+=zt(Math.trunc(-t.o/60)),l+=":",l+=zt(Math.trunc(-t.o%60))):(l+="+",l+=zt(Math.trunc(t.o/60)),l+=":",l+=zt(Math.trunc(t.o%60)))),r&&(l+="["+t.zone.ianaName+"]"),l}const si={month:1,day:1,hour:0,minute:0,second:0,millisecond:0},ai={weekNumber:1,weekday:1,hour:0,minute:0,second:0,millisecond:0},li={ordinal:1,hour:0,minute:0,second:0,millisecond:0},ci=["year","month","day","hour","minute","second","millisecond"],ui=["weekYear","weekNumber","weekday","hour","minute","second","millisecond"],di=["year","ordinal","hour","minute","second","millisecond"];function hi(t){const e={year:"year",years:"year",month:"month",months:"month",day:"day",days:"day",hour:"hour",hours:"hour",minute:"minute",minutes:"minute",quarter:"quarter",quarters:"quarter",second:"second",seconds:"second",millisecond:"millisecond",milliseconds:"millisecond",weekday:"weekday",weekdays:"weekday",weeknumber:"weekNumber",weeksnumber:"weekNumber",weeknumbers:"weekNumber",weekyear:"weekYear",weekyears:"weekYear",ordinal:"ordinal"}[t.toLowerCase()];if(!e)throw new l(t);return e}function pi(t){switch(t.toLowerCase()){case"localweekday":case"localweekdays":return"localWeekday";case"localweeknumber":case"localweeknumbers":return"localWeekNumber";case"localweekyear":case"localweekyears":return"localWeekYear";default:return hi(t)}}function mi(t,e){const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e);let o,r;if(jt(t.year))o=wt.now();else{for(const e of ci)jt(t[e])&&(t[e]=si[e]);const e=Pt(t)||Ft(t);if(e)return bi.invalid(e);const i=function(t){if(void 0===vi&&(vi=wt.now()),"iana"!==t.type)return t.offset(vi);const e=t.name;let n=yi.get(e);return void 0===n&&(n=t.offset(vi),yi.set(e,n)),n}(n);[o,r]=ti(t,i,n)}return new bi({ts:o,zone:n,loc:i,o:r})}function fi(t,e,n){const i=!!jt(n.round)||n.round,o=jt(n.rounding)?"trunc":n.rounding,r=(t,r)=>{t=Kt(t,i||n.calendary?0:2,n.calendary?"round":o);return e.loc.clone(n).relFormatter(n).format(t,r)},s=i=>n.calendary?e.hasSame(t,i)?0:e.startOf(i).diff(t.startOf(i),i).get(i):e.diff(t,i).get(i);if(n.unit)return r(s(n.unit),n.unit);for(const t of n.units){const e=s(t);if(Math.abs(e)>=1)return r(e,t)}return r(t>e?-0:0,n.units[n.units.length-1])}function gi(t){let e,n={};return t.length>0&&"object"==typeof t[t.length-1]?(n=t[t.length-1],e=Array.from(t).slice(0,t.length-1)):e=Array.from(t),[n,e]}let vi;const yi=new Map;class bi{constructor(t){const e=t.zone||wt.defaultZone;let n=t.invalid||(Number.isNaN(t.ts)?new kt("invalid input"):null)||(e.isValid?null:Zn(e));this.ts=jt(t.ts)?wt.now():t.ts;let i=null,o=null;if(!n){if(t.old&&t.old.ts===this.ts&&t.old.zone.equals(e))[i,o]=[t.old.c,t.old.o];else{const r=qt(t.o)&&!t.old?t.o:e.offset(this.ts);i=Qn(this.ts,r),n=Number.isNaN(i.year)?new kt("invalid input"):null,i=n?null:i,o=n?null:r}}this._zone=e,this.loc=t.loc||it.create(),this.invalid=n,this.weekData=null,this.localWeekData=null,this.c=i,this.o=o,this.isLuxonDateTime=!0}static now(){return new bi({})}static local(){const[t,e]=gi(arguments),[n,i,o,r,s,a,l]=e;return mi({year:n,month:i,day:o,hour:r,minute:s,second:a,millisecond:l},t)}static utc(){const[t,e]=gi(arguments),[n,i,o,r,s,a,l]=e;return t.zone=rt.utcInstance,mi({year:n,month:i,day:o,hour:r,minute:s,second:a,millisecond:l},t)}static fromJSDate(t,e={}){const n=(i=t,"[object Date]"===Object.prototype.toString.call(i)?t.valueOf():NaN);var i;if(Number.isNaN(n))return bi.invalid("invalid input");const o=at(e.zone,wt.defaultZone);return o.isValid?new bi({ts:n,zone:o,loc:it.fromObject(e)}):bi.invalid(Zn(o))}static fromMillis(t,e={}){if(qt(t))return t<-Un||t>Un?bi.invalid("Timestamp out of range"):new bi({ts:t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c(`fromMillis requires a numerical input, but received a ${typeof t} with value ${t}`)}static fromSeconds(t,e={}){if(qt(t))return new bi({ts:1e3*t,zone:at(e.zone,wt.defaultZone),loc:it.fromObject(e)});throw new c("fromSeconds requires a numerical input")}static fromObject(t,e={}){t=t||{};const n=at(e.zone,wt.defaultZone);if(!n.isValid)return bi.invalid(Zn(n));const i=it.fromObject(e),o=ae(t,pi),{minDaysInFirstWeek:r,startOfWeek:s}=Nt(o,i),l=wt.now(),c=jt(e.specificOffset)?n.offset(l):e.specificOffset,u=!jt(o.ordinal),d=!jt(o.year),h=!jt(o.month)||!jt(o.day),p=d||h,m=o.weekYear||o.weekNumber;if((p||u)&&m)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(h&&u)throw new a("Can't mix ordinal dates with month/day");const f=m||o.weekday&&!p;let g,v,y=Qn(l,c);f?(g=ui,v=ai,y=Lt(y,r,s)):u?(g=di,v=li,y=At(y)):(g=ci,v=si);let b=!1;for(const t of g){jt(o[t])?o[t]=b?v[t]:y[t]:b=!0}const _=f?function(t,e=4,n=1){const i=Ht(t.weekYear),o=Yt(t.weekNumber,1,ne(t.weekYear,e,n)),r=Yt(t.weekday,1,7);return i?o?!r&&Tt("weekday",t.weekday):Tt("week",t.weekNumber):Tt("weekYear",t.weekYear)}(o,r,s):u?function(t){const e=Ht(t.year),n=Yt(t.ordinal,1,Gt(t.year));return e?!n&&Tt("ordinal",t.ordinal):Tt("year",t.year)}(o):Pt(o),w=_||Ft(o);if(w)return bi.invalid(w);const k=f?Mt(o,r,s):u?It(o):o,[E,D]=ti(k,c,n),T=new bi({ts:E,zone:n,o:D,loc:i});return o.weekday&&p&&t.weekday!==T.weekday?bi.invalid("mismatched weekday",`you can't specify both a weekday of ${o.weekday} and a date of ${T.toISO()}`):T.isValid?T:bi.invalid(T.invalid)}static fromISO(t,e={}){const[n,i]=function(t){return Ce(t,[en,sn],[nn,an],[on,ln],[rn,cn])}(t);return ni(n,i,e,"ISO 8601",t)}static fromRFC2822(t,e={}){const[n,i]=function(t){return Ce(function(t){return t.replace(/\([^()]*\)|[\n\t]/g," ").replace(/(\s\s+)/g," ").trim()}(t),[Ze,Xe])}(t);return ni(n,i,e,"RFC 2822",t)}static fromHTTP(t,e={}){const[n,i]=function(t){return Ce(t,[Ke,Qe],[Je,Qe],[Ge,tn])}(t);return ni(n,i,e,"HTTP",e)}static fromFormat(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormat requires an input string and a format");const{locale:i=null,numberingSystem:o=null}=n,r=it.fromOpts({locale:i,numberingSystem:o,defaultToEN:!0}),[s,a,l,u]=function(t,e,n){const{result:i,zone:o,specificOffset:r,invalidReason:s}=Wn(t,e,n);return[i,o,r,s]}(r,t,e);return u?bi.invalid(u):ni(s,a,n,`format ${e}`,t,l)}static fromString(t,e,n={}){return bi.fromFormat(t,e,n)}static fromSQL(t,e={}){const[n,i]=function(t){return Ce(t,[dn,sn],[hn,pn])}(t);return ni(n,i,e,"SQL",t)}static invalid(t,e=null){if(!t)throw new c("need to specify a reason the DateTime is invalid");const n=t instanceof kt?t:new kt(t,e);if(wt.throwOnInvalid)throw new o(n);return new bi({invalid:n})}static isDateTime(t){return t&&t.isLuxonDateTime||!1}static parseFormatForOpts(t,e={}){const n=Yn(t,it.fromObject(e));return n?n.map((t=>t?t.val:null)).join(""):null}static expandFormat(t,e={}){return Bn(Te.parseFormat(t),it.fromObject(e)).map((t=>t.val)).join("")}static resetCache(){vi=void 0,yi.clear()}get(t){return this[t]}get isValid(){return null===this.invalid}get invalidReason(){return this.invalid?this.invalid.reason:null}get invalidExplanation(){return this.invalid?this.invalid.explanation:null}get locale(){return this.isValid?this.loc.locale:null}get numberingSystem(){return this.isValid?this.loc.numberingSystem:null}get outputCalendar(){return this.isValid?this.loc.outputCalendar:null}get zone(){return this._zone}get zoneName(){return this.isValid?this.zone.name:null}get year(){return this.isValid?this.c.year:NaN}get quarter(){return this.isValid?Math.ceil(this.c.month/3):NaN}get month(){return this.isValid?this.c.month:NaN}get day(){return this.isValid?this.c.day:NaN}get hour(){return this.isValid?this.c.hour:NaN}get minute(){return this.isValid?this.c.minute:NaN}get second(){return this.isValid?this.c.second:NaN}get millisecond(){return this.isValid?this.c.millisecond:NaN}get weekYear(){return this.isValid?Xn(this).weekYear:NaN}get weekNumber(){return this.isValid?Xn(this).weekNumber:NaN}get weekday(){return this.isValid?Xn(this).weekday:NaN}get isWeekend(){return this.isValid&&this.loc.getWeekendDays().includes(this.weekday)}get localWeekday(){return this.isValid?Kn(this).weekday:NaN}get localWeekNumber(){return this.isValid?Kn(this).weekNumber:NaN}get localWeekYear(){return this.isValid?Kn(this).weekYear:NaN}get ordinal(){return this.isValid?At(this.c).ordinal:NaN}get monthShort(){return this.isValid?Cn.months("short",{locObj:this.loc})[this.month-1]:null}get monthLong(){return this.isValid?Cn.months("long",{locObj:this.loc})[this.month-1]:null}get weekdayShort(){return this.isValid?Cn.weekdays("short",{locObj:this.loc})[this.weekday-1]:null}get weekdayLong(){return this.isValid?Cn.weekdays("long",{locObj:this.loc})[this.weekday-1]:null}get offset(){return this.isValid?+this.o:NaN}get offsetNameShort(){return this.isValid?this.zone.offsetName(this.ts,{format:"short",locale:this.locale}):null}get offsetNameLong(){return this.isValid?this.zone.offsetName(this.ts,{format:"long",locale:this.locale}):null}get isOffsetFixed(){return this.isValid?this.zone.isUniversal:null}get isInDST(){return!this.isOffsetFixed&&(this.offset>this.set({month:1,day:1}).offset||this.offset>this.set({month:5}).offset)}getPossibleOffsets(){if(!this.isValid||this.isOffsetFixed)return[this];const t=864e5,e=6e4,n=te(this.c),i=this.zone.offset(n-t),o=this.zone.offset(n+t),r=this.zone.offset(n-i*e),s=this.zone.offset(n-o*e);if(r===s)return[this];const a=n-r*e,l=n-s*e,c=Qn(a,r),u=Qn(l,s);return c.hour===u.hour&&c.minute===u.minute&&c.second===u.second&&c.millisecond===u.millisecond?[Jn(this,{ts:a}),Jn(this,{ts:l})]:[this]}get isInLeapYear(){return Jt(this.year)}get daysInMonth(){return Qt(this.year,this.month)}get daysInYear(){return this.isValid?Gt(this.year):NaN}get weeksInWeekYear(){return this.isValid?ne(this.weekYear):NaN}get weeksInLocalWeekYear(){return this.isValid?ne(this.localWeekYear,this.loc.getMinDaysInFirstWeek(),this.loc.getStartOfWeek()):NaN}resolvedLocaleOptions(t={}){const{locale:e,numberingSystem:n,calendar:i}=Te.create(this.loc.clone(t),t).resolvedOptions(this);return{locale:e,numberingSystem:n,outputCalendar:i}}toUTC(t=0,e={}){return this.setZone(rt.instance(t),e)}toLocal(){return this.setZone(wt.defaultZone)}setZone(t,{keepLocalTime:e=!1,keepCalendarTime:n=!1}={}){if((t=at(t,wt.defaultZone)).equals(this.zone))return this;if(t.isValid){let i=this.ts;if(e||n){const e=t.offset(this.ts),n=this.toObject();[i]=ti(n,e,t)}return Jn(this,{ts:i,zone:t})}return bi.invalid(Zn(t))}reconfigure({locale:t,numberingSystem:e,outputCalendar:n}={}){return Jn(this,{loc:this.loc.clone({locale:t,numberingSystem:e,outputCalendar:n})})}setLocale(t){return this.reconfigure({locale:t})}set(t){if(!this.isValid)return this;const e=ae(t,pi),{minDaysInFirstWeek:n,startOfWeek:i}=Nt(e,this.loc),o=!jt(e.weekYear)||!jt(e.weekNumber)||!jt(e.weekday),r=!jt(e.ordinal),s=!jt(e.year),l=!jt(e.month)||!jt(e.day),c=s||l,u=e.weekYear||e.weekNumber;if((c||r)&&u)throw new a("Can't mix weekYear/weekNumber units with year/month/day or ordinals");if(l&&r)throw new a("Can't mix ordinal dates with month/day");let d;o?d=Mt({...Lt(this.c,n,i),...e},n,i):jt(e.ordinal)?(d={...this.toObject(),...e},jt(e.day)&&(d.day=Math.min(Qt(d.year,d.month),d.day))):d=It({...At(this.c),...e});const[h,p]=ti(d,this.o,this.zone);return Jn(this,{ts:h,o:p})}plus(t){if(!this.isValid)return this;return Jn(this,ei(this,Sn.fromDurationLike(t)))}minus(t){if(!this.isValid)return this;return Jn(this,ei(this,Sn.fromDurationLike(t).negate()))}startOf(t,{useLocaleWeeks:e=!1}={}){if(!this.isValid)return this;const n={},i=Sn.normalizeUnit(t);switch(i){case"years":n.month=1;case"quarters":case"months":n.day=1;case"weeks":case"days":n.hour=0;case"hours":n.minute=0;case"minutes":n.second=0;case"seconds":n.millisecond=0}if("weeks"===i)if(e){const t=this.loc.getStartOfWeek(),{weekday:e}=this;e=3&&(a+="T"),a+=ri(this,s,e,n,i,o,r),a}toISODate({format:t="extended",precision:e="day"}={}){return this.isValid?oi(this,"extended"===t,hi(e)):null}toISOWeekDate(){return ii(this,"kkkk-'W'WW-c")}toISOTime({suppressMilliseconds:t=!1,suppressSeconds:e=!1,includeOffset:n=!0,includePrefix:i=!1,extendedZone:o=!1,format:r="extended",precision:s="milliseconds"}={}){if(!this.isValid)return null;return s=hi(s),(i&&ci.indexOf(s)>=3?"T":"")+ri(this,"extended"===r,e,t,n,o,s)}toRFC2822(){return ii(this,"EEE, dd LLL yyyy HH:mm:ss ZZZ",!1)}toHTTP(){return ii(this.toUTC(),"EEE, dd LLL yyyy HH:mm:ss 'GMT'")}toSQLDate(){return this.isValid?oi(this,!0):null}toSQLTime({includeOffset:t=!0,includeZone:e=!1,includeOffsetSpace:n=!0}={}){let i="HH:mm:ss.SSS";return(e||t)&&(n&&(i+=" "),e?i+="z":t&&(i+="ZZ")),ii(this,i,!0)}toSQL(t={}){return this.isValid?`${this.toSQLDate()} ${this.toSQLTime(t)}`:null}toString(){return this.isValid?this.toISO():zn}[Symbol.for("nodejs.util.inspect.custom")](){return this.isValid?`DateTime { ts: ${this.toISO()}, zone: ${this.zone.name}, locale: ${this.locale} }`:`DateTime { Invalid, reason: ${this.invalidReason} }`}valueOf(){return this.toMillis()}toMillis(){return this.isValid?this.ts:NaN}toSeconds(){return this.isValid?this.ts/1e3:NaN}toUnixInteger(){return this.isValid?Math.floor(this.ts/1e3):NaN}toJSON(){return this.toISO()}toBSON(){return this.toJSDate()}toObject(t={}){if(!this.isValid)return{};const e={...this.c};return t.includeConfig&&(e.outputCalendar=this.outputCalendar,e.numberingSystem=this.loc.numberingSystem,e.locale=this.loc.locale),e}toJSDate(){return new Date(this.isValid?this.ts:NaN)}diff(t,e="milliseconds",n={}){if(!this.isValid||!t.isValid)return Sn.invalid("created by diffing an invalid DateTime");const i={locale:this.locale,numberingSystem:this.numberingSystem,...n},o=(a=e,Array.isArray(a)?a:[a]).map(Sn.normalizeUnit),r=t.valueOf()>this.valueOf(),s=Mn(r?this:t,r?t:this,o,i);var a;return r?s.negate():s}diffNow(t="milliseconds",e={}){return this.diff(bi.now(),t,e)}until(t){return this.isValid?On.fromDateTimes(this,t):this}hasSame(t,e,n){if(!this.isValid)return!1;const i=t.valueOf(),o=this.setZone(t.zone,{keepLocalTime:!0});return o.startOf(e,n)<=i&&i<=o.endOf(e,n)}equals(t){return this.isValid&&t.isValid&&this.valueOf()===t.valueOf()&&this.zone.equals(t.zone)&&this.loc.equals(t.loc)}toRelative(t={}){if(!this.isValid)return null;const e=t.base||bi.fromObject({},{zone:this.zone}),n=t.padding?thist.valueOf()),Math.min)}static max(...t){if(!t.every(bi.isDateTime))throw new c("max requires all arguments be DateTimes");return Bt(t,(t=>t.valueOf()),Math.max)}static fromFormatExplain(t,e,n={}){const{locale:i=null,numberingSystem:o=null}=n;return Wn(it.fromOpts({locale:i,numberingSystem:o,defaultToEN:!0}),t,e)}static fromStringExplain(t,e,n={}){return bi.fromFormatExplain(t,e,n)}static buildFormatParser(t,e={}){const{locale:n=null,numberingSystem:i=null}=e,o=it.fromOpts({locale:n,numberingSystem:i,defaultToEN:!0});return new $n(o,t)}static fromFormatParser(t,e,n={}){if(jt(t)||jt(e))throw new c("fromFormatParser requires an input string and a format parser");const{locale:i=null,numberingSystem:o=null}=n,r=it.fromOpts({locale:i,numberingSystem:o,defaultToEN:!0});if(!r.equals(e.locale))throw new c(`fromFormatParser called with a locale of ${r}, but the format parser was created for ${e.locale}`);const{result:s,zone:a,specificOffset:l,invalidReason:u}=e.explainFromTokens(t);return u?bi.invalid(u):ni(s,a,n,`format ${e.format}`,t,l)}static get DATE_SHORT(){return m}static get DATE_MED(){return f}static get DATE_MED_WITH_WEEKDAY(){return g}static get DATE_FULL(){return v}static get DATE_HUGE(){return y}static get TIME_SIMPLE(){return b}static get TIME_WITH_SECONDS(){return _}static get TIME_WITH_SHORT_OFFSET(){return w}static get TIME_WITH_LONG_OFFSET(){return k}static get TIME_24_SIMPLE(){return E}static get TIME_24_WITH_SECONDS(){return D}static get TIME_24_WITH_SHORT_OFFSET(){return T}static get TIME_24_WITH_LONG_OFFSET(){return S}static get DATETIME_SHORT(){return x}static get DATETIME_SHORT_WITH_SECONDS(){return O}static get DATETIME_MED(){return C}static get DATETIME_MED_WITH_SECONDS(){return L}static get DATETIME_MED_WITH_WEEKDAY(){return M}static get DATETIME_FULL(){return A}static get DATETIME_FULL_WITH_SECONDS(){return I}static get DATETIME_HUGE(){return N}static get DATETIME_HUGE_WITH_SECONDS(){return P}}function _i(t){if(bi.isDateTime(t))return t;if(t&&t.valueOf&&qt(t.valueOf()))return bi.fromJSDate(t);if(t&&"object"==typeof t)return bi.fromObject(t);throw new c(`Unknown datetime argument: ${t}, of type ${typeof t}`)}},8214:function(){!function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=5)}([function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n,i,o,r=t[1]||"",s=t[3];if(!s)return r;if(e&&"function"==typeof btoa){var a=(n=s,i=btoa(unescape(encodeURIComponent(JSON.stringify(n)))),o="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(i),"/*# ".concat(o," */")),l=s.sources.map((function(t){return"/*# sourceURL=".concat(s.sourceRoot||"").concat(t," */")}));return[r].concat(l).concat([a]).join("\n")}return[r].join("\n")}(e,t);return e[2]?"@media ".concat(e[2]," {").concat(n,"}"):n})).join("")},e.i=function(t,n,i){"string"==typeof t&&(t=[[null,t,""]]);var o={};if(i)for(var r=0;rMath.abs(r),a=t.options.numberOfMonths,l=null,c=!1,u="",d=Array.from(t.ui.querySelectorAll(".month-item"));if(s){var h=t.DateTime(t.ui.querySelector(".day-item").dataset.time),p=Number("".concat(1-Math.abs(o)/100)),m=0;if(o>0){m=-Math.abs(o),l=h.clone().add(a,"month");var f=t.options.maxDate;c=!f||l.isSameOrBefore(t.DateTime(f),"month"),u="next"}else{m=Math.abs(o),l=h.clone().subtract(a,"month");var g=t.options.minDate;c=!g||l.isSameOrAfter(t.DateTime(g),"month"),u="prev"}c&&d.map((function(t){t.style.opacity=p,t.style.transform="translateX(".concat(m,"px)")}))}Math.abs(o)+Math.abs(r)>100&&s&&l&&c&&(t.touchTargetMonth=u,t.gotoDate(l))}}),!!n&&{passive:!0}),t.ui.addEventListener("touchend",(function(e){t.touchTargetMonth||Array.from(t.ui.querySelectorAll(".month-item")).map((function(t){t.style.transform="translateX(0px)",t.style.opacity=1})),t.xTouchDown=null,t.yTouchDown=null}),!!n&&{passive:!0})}})},function(t,e,n){var i=n(7);"string"==typeof i&&(i=[[t.i,i,""]]);var o={insert:function(t){var e=document.querySelector("head"),n=window._lastElementInsertedByStyleLoader;window.disableLitepickerStyles||(n?n.nextSibling?e.insertBefore(t,n.nextSibling):e.appendChild(t):e.insertBefore(t,e.firstChild),window._lastElementInsertedByStyleLoader=t)},singleton:!1};n(1)(i,o),i.locals&&(t.exports=i.locals)},function(t,e,n){(e=n(0)(!1)).push([t.i,':root {\n --litepicker-mobilefriendly-backdrop-color-bg: #000;\n}\n\n.litepicker-backdrop {\n display: none;\n background-color: var(--litepicker-mobilefriendly-backdrop-color-bg);\n opacity: 0.3;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n}\n\n.litepicker-open {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] {\n transform: translate(-50%, -50%);\n font-size: 1.1rem;\n --litepicker-container-months-box-shadow-color: #616161;\n}\n.litepicker.mobilefriendly-portrait {\n --litepicker-day-width: 13.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n.litepicker.mobilefriendly-landscape {\n --litepicker-day-width: 5.5vw;\n --litepicker-month-width: calc(var(--litepicker-day-width) * 7);\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months {\n overflow: hidden;\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__months .month-item-header {\n height: var(--litepicker-day-width);\n}\n\n.litepicker.mobilefriendly[data-plugins*="mobilefriendly"] .container__days > div {\n height: var(--litepicker-day-width);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item {\n transform-origin: center;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-next {\n animation-name: lp-bounce-target-next;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n.litepicker[data-plugins*="mobilefriendly"] .container__months .month-item.touch-target-prev {\n animation-name: lp-bounce-target-prev;\n animation-duration: .5s;\n animation-timing-function: ease;\n}\n\n@keyframes lp-bounce-target-next {\n from {\n transform: translateX(100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}\n\n@keyframes lp-bounce-target-prev {\n from {\n transform: translateX(-100px) scale(0.5);\n }\n to {\n transform: translateX(0px) scale(1);\n }\n}',""]),t.exports=e}])},9336:function(t,e,n){"use strict";n.d(e,{aF:function(){return Rn},go:function(){return Kn},AM:function(){return yi},y8:function(){return $i},m_:function(){return fi}});var i={};n.r(i),n.d(i,{afterMain:function(){return E},afterRead:function(){return _},afterWrite:function(){return S},applyStyles:function(){return I},arrow:function(){return Q},auto:function(){return l},basePlacements:function(){return c},beforeMain:function(){return w},beforeRead:function(){return y},beforeWrite:function(){return D},bottom:function(){return r},clippingParents:function(){return h},computeStyles:function(){return it},createPopper:function(){return It},createPopperBase:function(){return At},createPopperLite:function(){return Nt},detectOverflow:function(){return bt},end:function(){return d},eventListeners:function(){return rt},flip:function(){return _t},hide:function(){return Et},left:function(){return a},main:function(){return k},modifierPhases:function(){return x},offset:function(){return Dt},placements:function(){return v},popper:function(){return m},popperGenerator:function(){return Mt},popperOffsets:function(){return Tt},preventOverflow:function(){return St},read:function(){return b},reference:function(){return f},right:function(){return s},start:function(){return u},top:function(){return o},variationPlacements:function(){return g},viewport:function(){return p},write:function(){return T}});var o="top",r="bottom",s="right",a="left",l="auto",c=[o,r,s,a],u="start",d="end",h="clippingParents",p="viewport",m="popper",f="reference",g=c.reduce((function(t,e){return t.concat([e+"-"+u,e+"-"+d])}),[]),v=[].concat(c,[l]).reduce((function(t,e){return t.concat([e,e+"-"+u,e+"-"+d])}),[]),y="beforeRead",b="read",_="afterRead",w="beforeMain",k="main",E="afterMain",D="beforeWrite",T="write",S="afterWrite",x=[y,b,_,w,k,E,D,T,S];function O(t){return t?(t.nodeName||"").toLowerCase():null}function C(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function L(t){return t instanceof C(t).Element||t instanceof Element}function M(t){return t instanceof C(t).HTMLElement||t instanceof HTMLElement}function A(t){return"undefined"!=typeof ShadowRoot&&(t instanceof C(t).ShadowRoot||t instanceof ShadowRoot)}var I={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var n=e.styles[t]||{},i=e.attributes[t]||{},o=e.elements[t];M(o)&&O(o)&&(Object.assign(o.style,n),Object.keys(i).forEach((function(t){var e=i[t];!1===e?o.removeAttribute(t):o.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,n={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,n.popper),e.styles=n,e.elements.arrow&&Object.assign(e.elements.arrow.style,n.arrow),function(){Object.keys(e.elements).forEach((function(t){var i=e.elements[t],o=e.attributes[t]||{},r=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:n[t]).reduce((function(t,e){return t[e]="",t}),{});M(i)&&O(i)&&(Object.assign(i.style,r),Object.keys(o).forEach((function(t){i.removeAttribute(t)})))}))}},requires:["computeStyles"]};function N(t){return t.split("-")[0]}var P=Math.max,F=Math.min,j=Math.round;function q(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map((function(t){return t.brand+"/"+t.version})).join(" "):navigator.userAgent}function H(){return!/^((?!chrome|android).)*safari/i.test(q())}function V(t,e,n){void 0===e&&(e=!1),void 0===n&&(n=!1);var i=t.getBoundingClientRect(),o=1,r=1;e&&M(t)&&(o=t.offsetWidth>0&&j(i.width)/t.offsetWidth||1,r=t.offsetHeight>0&&j(i.height)/t.offsetHeight||1);var s=(L(t)?C(t):window).visualViewport,a=!H()&&n,l=(i.left+(a&&s?s.offsetLeft:0))/o,c=(i.top+(a&&s?s.offsetTop:0))/r,u=i.width/o,d=i.height/r;return{width:u,height:d,top:c,right:l+u,bottom:c+d,left:l,x:l,y:c}}function R(t){var e=V(t),n=t.offsetWidth,i=t.offsetHeight;return Math.abs(e.width-n)<=1&&(n=e.width),Math.abs(e.height-i)<=1&&(i=e.height),{x:t.offsetLeft,y:t.offsetTop,width:n,height:i}}function B(t,e){var n=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(n&&A(n)){var i=e;do{if(i&&t.isSameNode(i))return!0;i=i.parentNode||i.host}while(i)}return!1}function $(t){return C(t).getComputedStyle(t)}function W(t){return["table","td","th"].indexOf(O(t))>=0}function Y(t){return((L(t)?t.ownerDocument:t.document)||window.document).documentElement}function z(t){return"html"===O(t)?t:t.assignedSlot||t.parentNode||(A(t)?t.host:null)||Y(t)}function U(t){return M(t)&&"fixed"!==$(t).position?t.offsetParent:null}function Z(t){for(var e=C(t),n=U(t);n&&W(n)&&"static"===$(n).position;)n=U(n);return n&&("html"===O(n)||"body"===O(n)&&"static"===$(n).position)?e:n||function(t){var e=/firefox/i.test(q());if(/Trident/i.test(q())&&M(t)&&"fixed"===$(t).position)return null;var n=z(t);for(A(n)&&(n=n.host);M(n)&&["html","body"].indexOf(O(n))<0;){var i=$(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||e&&"filter"===i.willChange||e&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(t)||e}function X(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function K(t,e,n){return P(t,F(e,n))}function J(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function G(t,e){return e.reduce((function(e,n){return e[n]=t,e}),{})}var Q={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,n=t.state,i=t.name,l=t.options,u=n.elements.arrow,d=n.modifiersData.popperOffsets,h=N(n.placement),p=X(h),m=[a,s].indexOf(h)>=0?"height":"width";if(u&&d){var f=function(t,e){return J("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:G(t,c))}(l.padding,n),g=R(u),v="y"===p?o:a,y="y"===p?r:s,b=n.rects.reference[m]+n.rects.reference[p]-d[p]-n.rects.popper[m],_=d[p]-n.rects.reference[p],w=Z(u),k=w?"y"===p?w.clientHeight||0:w.clientWidth||0:0,E=b/2-_/2,D=f[v],T=k-g[m]-f[y],S=k/2-g[m]/2+E,x=K(D,S,T),O=p;n.modifiersData[i]=((e={})[O]=x,e.centerOffset=x-S,e)}},effect:function(t){var e=t.state,n=t.options.element,i=void 0===n?"[data-popper-arrow]":n;null!=i&&("string"!=typeof i||(i=e.elements.popper.querySelector(i)))&&B(e.elements.popper,i)&&(e.elements.arrow=i)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function tt(t){return t.split("-")[1]}var et={top:"auto",right:"auto",bottom:"auto",left:"auto"};function nt(t){var e,n=t.popper,i=t.popperRect,l=t.placement,c=t.variation,u=t.offsets,h=t.position,p=t.gpuAcceleration,m=t.adaptive,f=t.roundOffsets,g=t.isFixed,v=u.x,y=void 0===v?0:v,b=u.y,_=void 0===b?0:b,w="function"==typeof f?f({x:y,y:_}):{x:y,y:_};y=w.x,_=w.y;var k=u.hasOwnProperty("x"),E=u.hasOwnProperty("y"),D=a,T=o,S=window;if(m){var x=Z(n),O="clientHeight",L="clientWidth";if(x===C(n)&&"static"!==$(x=Y(n)).position&&"absolute"===h&&(O="scrollHeight",L="scrollWidth"),l===o||(l===a||l===s)&&c===d)T=r,_-=(g&&x===S&&S.visualViewport?S.visualViewport.height:x[O])-i.height,_*=p?1:-1;if(l===a||(l===o||l===r)&&c===d)D=s,y-=(g&&x===S&&S.visualViewport?S.visualViewport.width:x[L])-i.width,y*=p?1:-1}var M,A=Object.assign({position:h},m&&et),I=!0===f?function(t,e){var n=t.x,i=t.y,o=e.devicePixelRatio||1;return{x:j(n*o)/o||0,y:j(i*o)/o||0}}({x:y,y:_},C(n)):{x:y,y:_};return y=I.x,_=I.y,p?Object.assign({},A,((M={})[T]=E?"0":"",M[D]=k?"0":"",M.transform=(S.devicePixelRatio||1)<=1?"translate("+y+"px, "+_+"px)":"translate3d("+y+"px, "+_+"px, 0)",M)):Object.assign({},A,((e={})[T]=E?_+"px":"",e[D]=k?y+"px":"",e.transform="",e))}var it={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,n=t.options,i=n.gpuAcceleration,o=void 0===i||i,r=n.adaptive,s=void 0===r||r,a=n.roundOffsets,l=void 0===a||a,c={placement:N(e.placement),variation:tt(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:o,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,nt(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:s,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,nt(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}},ot={passive:!0};var rt={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,n=t.instance,i=t.options,o=i.scroll,r=void 0===o||o,s=i.resize,a=void 0===s||s,l=C(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return r&&c.forEach((function(t){t.addEventListener("scroll",n.update,ot)})),a&&l.addEventListener("resize",n.update,ot),function(){r&&c.forEach((function(t){t.removeEventListener("scroll",n.update,ot)})),a&&l.removeEventListener("resize",n.update,ot)}},data:{}},st={left:"right",right:"left",bottom:"top",top:"bottom"};function at(t){return t.replace(/left|right|bottom|top/g,(function(t){return st[t]}))}var lt={start:"end",end:"start"};function ct(t){return t.replace(/start|end/g,(function(t){return lt[t]}))}function ut(t){var e=C(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function dt(t){return V(Y(t)).left+ut(t).scrollLeft}function ht(t){var e=$(t),n=e.overflow,i=e.overflowX,o=e.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+i)}function pt(t){return["html","body","#document"].indexOf(O(t))>=0?t.ownerDocument.body:M(t)&&ht(t)?t:pt(z(t))}function mt(t,e){var n;void 0===e&&(e=[]);var i=pt(t),o=i===(null==(n=t.ownerDocument)?void 0:n.body),r=C(i),s=o?[r].concat(r.visualViewport||[],ht(i)?i:[]):i,a=e.concat(s);return o?a:a.concat(mt(z(s)))}function ft(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function gt(t,e,n){return e===p?ft(function(t,e){var n=C(t),i=Y(t),o=n.visualViewport,r=i.clientWidth,s=i.clientHeight,a=0,l=0;if(o){r=o.width,s=o.height;var c=H();(c||!c&&"fixed"===e)&&(a=o.offsetLeft,l=o.offsetTop)}return{width:r,height:s,x:a+dt(t),y:l}}(t,n)):L(e)?function(t,e){var n=V(t,!1,"fixed"===e);return n.top=n.top+t.clientTop,n.left=n.left+t.clientLeft,n.bottom=n.top+t.clientHeight,n.right=n.left+t.clientWidth,n.width=t.clientWidth,n.height=t.clientHeight,n.x=n.left,n.y=n.top,n}(e,n):ft(function(t){var e,n=Y(t),i=ut(t),o=null==(e=t.ownerDocument)?void 0:e.body,r=P(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=P(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),a=-i.scrollLeft+dt(t),l=-i.scrollTop;return"rtl"===$(o||n).direction&&(a+=P(n.clientWidth,o?o.clientWidth:0)-r),{width:r,height:s,x:a,y:l}}(Y(t)))}function vt(t,e,n,i){var o="clippingParents"===e?function(t){var e=mt(z(t)),n=["absolute","fixed"].indexOf($(t).position)>=0&&M(t)?Z(t):t;return L(n)?e.filter((function(t){return L(t)&&B(t,n)&&"body"!==O(t)})):[]}(t):[].concat(e),r=[].concat(o,[n]),s=r[0],a=r.reduce((function(e,n){var o=gt(t,n,i);return e.top=P(o.top,e.top),e.right=F(o.right,e.right),e.bottom=F(o.bottom,e.bottom),e.left=P(o.left,e.left),e}),gt(t,s,i));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}function yt(t){var e,n=t.reference,i=t.element,l=t.placement,c=l?N(l):null,h=l?tt(l):null,p=n.x+n.width/2-i.width/2,m=n.y+n.height/2-i.height/2;switch(c){case o:e={x:p,y:n.y-i.height};break;case r:e={x:p,y:n.y+n.height};break;case s:e={x:n.x+n.width,y:m};break;case a:e={x:n.x-i.width,y:m};break;default:e={x:n.x,y:n.y}}var f=c?X(c):null;if(null!=f){var g="y"===f?"height":"width";switch(h){case u:e[f]=e[f]-(n[g]/2-i[g]/2);break;case d:e[f]=e[f]+(n[g]/2-i[g]/2)}}return e}function bt(t,e){void 0===e&&(e={});var n=e,i=n.placement,a=void 0===i?t.placement:i,l=n.strategy,u=void 0===l?t.strategy:l,d=n.boundary,g=void 0===d?h:d,v=n.rootBoundary,y=void 0===v?p:v,b=n.elementContext,_=void 0===b?m:b,w=n.altBoundary,k=void 0!==w&&w,E=n.padding,D=void 0===E?0:E,T=J("number"!=typeof D?D:G(D,c)),S=_===m?f:m,x=t.rects.popper,O=t.elements[k?S:_],C=vt(L(O)?O:O.contextElement||Y(t.elements.popper),g,y,u),M=V(t.elements.reference),A=yt({reference:M,element:x,strategy:"absolute",placement:a}),I=ft(Object.assign({},x,A)),N=_===m?I:M,P={top:C.top-N.top+T.top,bottom:N.bottom-C.bottom+T.bottom,left:C.left-N.left+T.left,right:N.right-C.right+T.right},F=t.modifiersData.offset;if(_===m&&F){var j=F[a];Object.keys(P).forEach((function(t){var e=[s,r].indexOf(t)>=0?1:-1,n=[o,r].indexOf(t)>=0?"y":"x";P[t]+=j[n]*e}))}return P}var _t={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,n=t.options,i=t.name;if(!e.modifiersData[i]._skip){for(var d=n.mainAxis,h=void 0===d||d,p=n.altAxis,m=void 0===p||p,f=n.fallbackPlacements,y=n.padding,b=n.boundary,_=n.rootBoundary,w=n.altBoundary,k=n.flipVariations,E=void 0===k||k,D=n.allowedAutoPlacements,T=e.options.placement,S=N(T),x=f||(S===T||!E?[at(T)]:function(t){if(N(t)===l)return[];var e=at(t);return[ct(t),e,ct(e)]}(T)),O=[T].concat(x).reduce((function(t,n){return t.concat(N(n)===l?function(t,e){void 0===e&&(e={});var n=e,i=n.placement,o=n.boundary,r=n.rootBoundary,s=n.padding,a=n.flipVariations,l=n.allowedAutoPlacements,u=void 0===l?v:l,d=tt(i),h=d?a?g:g.filter((function(t){return tt(t)===d})):c,p=h.filter((function(t){return u.indexOf(t)>=0}));0===p.length&&(p=h);var m=p.reduce((function(e,n){return e[n]=bt(t,{placement:n,boundary:o,rootBoundary:r,padding:s})[N(n)],e}),{});return Object.keys(m).sort((function(t,e){return m[t]-m[e]}))}(e,{placement:n,boundary:b,rootBoundary:_,padding:y,flipVariations:E,allowedAutoPlacements:D}):n)}),[]),C=e.rects.reference,L=e.rects.popper,M=new Map,A=!0,I=O[0],P=0;P=0,V=H?"width":"height",R=bt(e,{placement:F,boundary:b,rootBoundary:_,altBoundary:w,padding:y}),B=H?q?s:a:q?r:o;C[V]>L[V]&&(B=at(B));var $=at(B),W=[];if(h&&W.push(R[j]<=0),m&&W.push(R[B]<=0,R[$]<=0),W.every((function(t){return t}))){I=F,A=!1;break}M.set(F,W)}if(A)for(var Y=function(t){var e=O.find((function(e){var n=M.get(e);if(n)return n.slice(0,t).every((function(t){return t}))}));if(e)return I=e,"break"},z=E?3:1;z>0;z--){if("break"===Y(z))break}e.placement!==I&&(e.modifiersData[i]._skip=!0,e.placement=I,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function wt(t,e,n){return void 0===n&&(n={x:0,y:0}),{top:t.top-e.height-n.y,right:t.right-e.width+n.x,bottom:t.bottom-e.height+n.y,left:t.left-e.width-n.x}}function kt(t){return[o,s,r,a].some((function(e){return t[e]>=0}))}var Et={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,n=t.name,i=e.rects.reference,o=e.rects.popper,r=e.modifiersData.preventOverflow,s=bt(e,{elementContext:"reference"}),a=bt(e,{altBoundary:!0}),l=wt(s,i),c=wt(a,o,r),u=kt(l),d=kt(c);e.modifiersData[n]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:u,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":u,"data-popper-escaped":d})}};var Dt={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,n=t.options,i=t.name,r=n.offset,l=void 0===r?[0,0]:r,c=v.reduce((function(t,n){return t[n]=function(t,e,n){var i=N(t),r=[a,o].indexOf(i)>=0?-1:1,l="function"==typeof n?n(Object.assign({},e,{placement:t})):n,c=l[0],u=l[1];return c=c||0,u=(u||0)*r,[a,s].indexOf(i)>=0?{x:u,y:c}:{x:c,y:u}}(n,e.rects,l),t}),{}),u=c[e.placement],d=u.x,h=u.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=d,e.modifiersData.popperOffsets.y+=h),e.modifiersData[i]=c}};var Tt={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,n=t.name;e.modifiersData[n]=yt({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}};var St={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,n=t.options,i=t.name,l=n.mainAxis,c=void 0===l||l,d=n.altAxis,h=void 0!==d&&d,p=n.boundary,m=n.rootBoundary,f=n.altBoundary,g=n.padding,v=n.tether,y=void 0===v||v,b=n.tetherOffset,_=void 0===b?0:b,w=bt(e,{boundary:p,rootBoundary:m,padding:g,altBoundary:f}),k=N(e.placement),E=tt(e.placement),D=!E,T=X(k),S="x"===T?"y":"x",x=e.modifiersData.popperOffsets,O=e.rects.reference,C=e.rects.popper,L="function"==typeof _?_(Object.assign({},e.rects,{placement:e.placement})):_,M="number"==typeof L?{mainAxis:L,altAxis:L}:Object.assign({mainAxis:0,altAxis:0},L),A=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,I={x:0,y:0};if(x){if(c){var j,q="y"===T?o:a,H="y"===T?r:s,V="y"===T?"height":"width",B=x[T],$=B+w[q],W=B-w[H],Y=y?-C[V]/2:0,z=E===u?O[V]:C[V],U=E===u?-C[V]:-O[V],J=e.elements.arrow,G=y&&J?R(J):{width:0,height:0},Q=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},et=Q[q],nt=Q[H],it=K(0,O[V],G[V]),ot=D?O[V]/2-Y-it-et-M.mainAxis:z-it-et-M.mainAxis,rt=D?-O[V]/2+Y+it+nt+M.mainAxis:U+it+nt+M.mainAxis,st=e.elements.arrow&&Z(e.elements.arrow),at=st?"y"===T?st.clientTop||0:st.clientLeft||0:0,lt=null!=(j=null==A?void 0:A[T])?j:0,ct=B+rt-lt,ut=K(y?F($,B+ot-lt-at):$,B,y?P(W,ct):W);x[T]=ut,I[T]=ut-B}if(h){var dt,ht="x"===T?o:a,pt="x"===T?r:s,mt=x[S],ft="y"===S?"height":"width",gt=mt+w[ht],vt=mt-w[pt],yt=-1!==[o,a].indexOf(k),_t=null!=(dt=null==A?void 0:A[S])?dt:0,wt=yt?gt:mt-O[ft]-C[ft]-_t+M.altAxis,kt=yt?mt+O[ft]+C[ft]-_t-M.altAxis:vt,Et=y&&yt?function(t,e,n){var i=K(t,e,n);return i>n?n:i}(wt,mt,kt):K(y?wt:gt,mt,y?kt:vt);x[S]=Et,I[S]=Et-mt}e.modifiersData[i]=I}},requiresIfExists:["offset"]};function xt(t,e,n){void 0===n&&(n=!1);var i,o,r=M(e),s=M(e)&&function(t){var e=t.getBoundingClientRect(),n=j(e.width)/t.offsetWidth||1,i=j(e.height)/t.offsetHeight||1;return 1!==n||1!==i}(e),a=Y(e),l=V(t,s,n),c={scrollLeft:0,scrollTop:0},u={x:0,y:0};return(r||!r&&!n)&&(("body"!==O(e)||ht(a))&&(c=(i=e)!==C(i)&&M(i)?{scrollLeft:(o=i).scrollLeft,scrollTop:o.scrollTop}:ut(i)),M(e)?((u=V(e,!0)).x+=e.clientLeft,u.y+=e.clientTop):a&&(u.x=dt(a))),{x:l.left+c.scrollLeft-u.x,y:l.top+c.scrollTop-u.y,width:l.width,height:l.height}}function Ot(t){var e=new Map,n=new Set,i=[];function o(t){n.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!n.has(t)){var i=e.get(t);i&&o(i)}})),i.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){n.has(t.name)||o(t)})),i}var Ct={placement:"bottom",modifiers:[],strategy:"absolute"};function Lt(){for(var t=arguments.length,e=new Array(t),n=0;nPt.has(t)&&Pt.get(t).get(e)||null,remove(t,e){if(!Pt.has(t))return;const n=Pt.get(t);n.delete(e),0===n.size&&Pt.delete(t)}},jt="transitionend",qt=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,((t,e)=>`#${CSS.escape(e)}`))),t),Ht=t=>{t.dispatchEvent(new Event(jt))},Vt=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),Rt=t=>Vt(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(qt(t)):null,Bt=t=>{if(!Vt(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),n=t.closest("details:not([open])");if(!n)return e;if(n!==t){const e=t.closest("summary");if(e&&e.parentNode!==n)return!1;if(null===e)return!1}return e},$t=t=>!t||t.nodeType!==Node.ELEMENT_NODE||(!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled"))),Wt=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?Wt(t.parentNode):null},Yt=()=>{},zt=t=>{t.offsetHeight},Ut=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,Zt=[],Xt=()=>"rtl"===document.documentElement.dir,Kt=t=>{var e;e=()=>{const e=Ut();if(e){const n=t.NAME,i=e.fn[n];e.fn[n]=t.jQueryInterface,e.fn[n].Constructor=t,e.fn[n].noConflict=()=>(e.fn[n]=i,t.jQueryInterface)}},"loading"===document.readyState?(Zt.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of Zt)t()})),Zt.push(e)):e()},Jt=(t,e=[],n=t)=>"function"==typeof t?t.call(...e):n,Gt=(t,e,n=!0)=>{if(!n)return void Jt(t);const i=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:n}=window.getComputedStyle(t);const i=Number.parseFloat(e),o=Number.parseFloat(n);return i||o?(e=e.split(",")[0],n=n.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(n))):0})(e)+5;let o=!1;const r=({target:n})=>{n===e&&(o=!0,e.removeEventListener(jt,r),Jt(t))};e.addEventListener(jt,r),setTimeout((()=>{o||Ht(e)}),i)},Qt=(t,e,n,i)=>{const o=t.length;let r=t.indexOf(e);return-1===r?!n&&i?t[o-1]:t[0]:(r+=n?1:-1,i&&(r=(r+o)%o),t[Math.max(0,Math.min(r,o-1))])},te=/[^.]*(?=\..*)\.|.*/,ee=/\..*/,ne=/::\d+$/,ie={};let oe=1;const re={mouseenter:"mouseover",mouseleave:"mouseout"},se=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function ae(t,e){return e&&`${e}::${oe++}`||t.uidEvent||oe++}function le(t){const e=ae(t);return t.uidEvent=e,ie[e]=ie[e]||{},ie[e]}function ce(t,e,n=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===n))}function ue(t,e,n){const i="string"==typeof e,o=i?n:e||n;let r=me(t);return se.has(r)||(r=t),[i,o,r]}function de(t,e,n,i,o){if("string"!=typeof e||!t)return;let[r,s,a]=ue(e,n,i);if(e in re){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};s=t(s)}const l=le(t),c=l[a]||(l[a]={}),u=ce(c,s,r?n:null);if(u)return void(u.oneOff=u.oneOff&&o);const d=ae(s,e.replace(te,"")),h=r?function(t,e,n){return function i(o){const r=t.querySelectorAll(e);for(let{target:s}=o;s&&s!==this;s=s.parentNode)for(const a of r)if(a===s)return ge(o,{delegateTarget:s}),i.oneOff&&fe.off(t,o.type,e,n),n.apply(s,[o])}}(t,n,s):function(t,e){return function n(i){return ge(i,{delegateTarget:t}),n.oneOff&&fe.off(t,i.type,e),e.apply(t,[i])}}(t,s);h.delegationSelector=r?n:null,h.callable=s,h.oneOff=o,h.uidEvent=d,c[d]=h,t.addEventListener(a,h,r)}function he(t,e,n,i,o){const r=ce(e[n],i,o);r&&(t.removeEventListener(n,r,Boolean(o)),delete e[n][r.uidEvent])}function pe(t,e,n,i){const o=e[n]||{};for(const[r,s]of Object.entries(o))r.includes(i)&&he(t,e,n,s.callable,s.delegationSelector)}function me(t){return t=t.replace(ee,""),re[t]||t}const fe={on(t,e,n,i){de(t,e,n,i,!1)},one(t,e,n,i){de(t,e,n,i,!0)},off(t,e,n,i){if("string"!=typeof e||!t)return;const[o,r,s]=ue(e,n,i),a=s!==e,l=le(t),c=l[s]||{},u=e.startsWith(".");if(void 0===r){if(u)for(const n of Object.keys(l))pe(t,l,n,e.slice(1));for(const[n,i]of Object.entries(c)){const o=n.replace(ne,"");a&&!e.includes(o)||he(t,l,s,i.callable,i.delegationSelector)}}else{if(!Object.keys(c).length)return;he(t,l,s,r,o?n:null)}},trigger(t,e,n){if("string"!=typeof e||!t)return null;const i=Ut();let o=null,r=!0,s=!0,a=!1;e!==me(e)&&i&&(o=i.Event(e,n),i(t).trigger(o),r=!o.isPropagationStopped(),s=!o.isImmediatePropagationStopped(),a=o.isDefaultPrevented());const l=ge(new Event(e,{bubbles:r,cancelable:!0}),n);return a&&l.preventDefault(),s&&t.dispatchEvent(l),l.defaultPrevented&&o&&o.preventDefault(),l}};function ge(t,e={}){for(const[n,i]of Object.entries(e))try{t[n]=i}catch(e){Object.defineProperty(t,n,{configurable:!0,get:()=>i})}return t}function ve(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function ye(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const be={setDataAttribute(t,e,n){t.setAttribute(`data-bs-${ye(e)}`,n)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${ye(e)}`)},getDataAttributes(t){if(!t)return{};const e={},n=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const i of n){let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1),e[n]=ve(t.dataset[i])}return e},getDataAttribute:(t,e)=>ve(t.getAttribute(`data-bs-${ye(e)}`))};class _e{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const n=Vt(e)?be.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof n?n:{},...Vt(e)?be.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[i,o]of Object.entries(e)){const e=t[i],r=Vt(e)?"element":null==(n=e)?`${n}`:Object.prototype.toString.call(n).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(o).test(r))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${i}" provided type "${r}" but expected type "${o}".`)}var n}}class we extends _e{constructor(t,e){super(),(t=Rt(t))&&(this._element=t,this._config=this._getConfig(e),Ft.set(this._element,this.constructor.DATA_KEY,this))}dispose(){Ft.remove(this._element,this.constructor.DATA_KEY),fe.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,n=!0){Gt(t,e,n)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return Ft.get(Rt(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.8"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const ke=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let n=t.getAttribute("href");if(!n||!n.includes("#")&&!n.startsWith("."))return null;n.includes("#")&&!n.startsWith("#")&&(n=`#${n.split("#")[1]}`),e=n&&"#"!==n?n.trim():null}return e?e.split(",").map((t=>qt(t))).join(","):null},Ee={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const n=[];let i=t.parentNode.closest(e);for(;i;)n.push(i),i=i.parentNode.closest(e);return n},prev(t,e){let n=t.previousElementSibling;for(;n;){if(n.matches(e))return[n];n=n.previousElementSibling}return[]},next(t,e){let n=t.nextElementSibling;for(;n;){if(n.matches(e))return[n];n=n.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!$t(t)&&Bt(t)))},getSelectorFromElement(t){const e=ke(t);return e&&Ee.findOne(e)?e:null},getElementFromSelector(t){const e=ke(t);return e?Ee.findOne(e):null},getMultipleElementsFromSelector(t){const e=ke(t);return e?Ee.find(e):[]}},De=(t,e="hide")=>{const n=`click.dismiss${t.EVENT_KEY}`,i=t.NAME;fe.on(document,n,`[data-bs-dismiss="${i}"]`,(function(n){if(["A","AREA"].includes(this.tagName)&&n.preventDefault(),$t(this))return;const o=Ee.getElementFromSelector(this)||this.closest(`.${i}`);t.getOrCreateInstance(o)[e]()}))};class Te extends we{static get NAME(){return"alert"}close(){if(fe.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),fe.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=Te.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}De(Te,"close"),Kt(Te);const Se='[data-bs-toggle="button"]';class xe extends we{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=xe.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}fe.on(document,"click.bs.button.data-api",Se,(t=>{t.preventDefault();const e=t.target.closest(Se);xe.getOrCreateInstance(e).toggle()})),Kt(xe);const Oe=".bs.swipe",Ce={endCallback:null,leftCallback:null,rightCallback:null},Le={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class Me extends _e{constructor(t,e){super(),this._element=t,t&&Me.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return Ce}static get DefaultType(){return Le}static get NAME(){return"swipe"}dispose(){fe.off(this._element,Oe)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),Jt(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&Jt(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(fe.on(this._element,"pointerdown.bs.swipe",(t=>this._start(t))),fe.on(this._element,"pointerup.bs.swipe",(t=>this._end(t))),this._element.classList.add("pointer-event")):(fe.on(this._element,"touchstart.bs.swipe",(t=>this._start(t))),fe.on(this._element,"touchmove.bs.swipe",(t=>this._move(t))),fe.on(this._element,"touchend.bs.swipe",(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const Ae="next",Ie="prev",Ne="left",Pe="right",Fe="slid.bs.carousel",je="carousel",qe="active",He=".active",Ve=".carousel-item",Re={ArrowLeft:Pe,ArrowRight:Ne},Be={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},$e={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class We extends we{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=Ee.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===je&&this.cycle()}static get Default(){return Be}static get DefaultType(){return $e}static get NAME(){return"carousel"}next(){this._slide(Ae)}nextWhenVisible(){!document.hidden&&Bt(this._element)&&this.next()}prev(){this._slide(Ie)}pause(){this._isSliding&&Ht(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?fe.one(this._element,Fe,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void fe.one(this._element,Fe,(()=>this.to(t)));const n=this._getItemIndex(this._getActive());if(n===t)return;const i=t>n?Ae:Ie;this._slide(i,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&fe.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(fe.on(this._element,"mouseenter.bs.carousel",(()=>this.pause())),fe.on(this._element,"mouseleave.bs.carousel",(()=>this._maybeEnableCycle()))),this._config.touch&&Me.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of Ee.find(".carousel-item img",this._element))fe.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(Ne)),rightCallback:()=>this._slide(this._directionToOrder(Pe)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new Me(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=Re[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=Ee.findOne(He,this._indicatorsElement);e.classList.remove(qe),e.removeAttribute("aria-current");const n=Ee.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);n&&(n.classList.add(qe),n.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const n=this._getActive(),i=t===Ae,o=e||Qt(this._getItems(),n,i,this._config.wrap);if(o===n)return;const r=this._getItemIndex(o),s=e=>fe.trigger(this._element,e,{relatedTarget:o,direction:this._orderToDirection(t),from:this._getItemIndex(n),to:r});if(s("slide.bs.carousel").defaultPrevented)return;if(!n||!o)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(r),this._activeElement=o;const l=i?"carousel-item-start":"carousel-item-end",c=i?"carousel-item-next":"carousel-item-prev";o.classList.add(c),zt(o),n.classList.add(l),o.classList.add(l);this._queueCallback((()=>{o.classList.remove(l,c),o.classList.add(qe),n.classList.remove(qe,c,l),this._isSliding=!1,s(Fe)}),n,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return Ee.findOne(".active.carousel-item",this._element)}_getItems(){return Ee.find(Ve,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return Xt()?t===Ne?Ie:Ae:t===Ne?Ae:Ie}_orderToDirection(t){return Xt()?t===Ie?Ne:Pe:t===Ie?Pe:Ne}static jQueryInterface(t){return this.each((function(){const e=We.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}fe.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",(function(t){const e=Ee.getElementFromSelector(this);if(!e||!e.classList.contains(je))return;t.preventDefault();const n=We.getOrCreateInstance(e),i=this.getAttribute("data-bs-slide-to");return i?(n.to(i),void n._maybeEnableCycle()):"next"===be.getDataAttribute(this,"slide")?(n.next(),void n._maybeEnableCycle()):(n.prev(),void n._maybeEnableCycle())})),fe.on(window,"load.bs.carousel.data-api",(()=>{const t=Ee.find('[data-bs-ride="carousel"]');for(const e of t)We.getOrCreateInstance(e)})),Kt(We);const Ye="show",ze="collapse",Ue="collapsing",Ze='[data-bs-toggle="collapse"]',Xe={parent:null,toggle:!0},Ke={parent:"(null|element)",toggle:"boolean"};class Je extends we{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const n=Ee.find(Ze);for(const t of n){const e=Ee.getSelectorFromElement(t),n=Ee.find(e).filter((t=>t===this._element));null!==e&&n.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return Xe}static get DefaultType(){return Ke}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>Je.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(fe.trigger(this._element,"show.bs.collapse").defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(ze),this._element.classList.add(Ue),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const n=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ue),this._element.classList.add(ze,Ye),this._element.style[e]="",fe.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[e]=`${this._element[n]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(fe.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,zt(this._element),this._element.classList.add(Ue),this._element.classList.remove(ze,Ye);for(const t of this._triggerArray){const e=Ee.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0;this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(Ue),this._element.classList.add(ze),fe.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(Ye)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=Rt(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Ze);for(const e of t){const t=Ee.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=Ee.find(":scope .collapse .collapse",this._config.parent);return Ee.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const n of t)n.classList.toggle("collapsed",!e),n.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const n=Je.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===n[t])throw new TypeError(`No method named "${t}"`);n[t]()}}))}}fe.on(document,"click.bs.collapse.data-api",Ze,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of Ee.getMultipleElementsFromSelector(this))Je.getOrCreateInstance(t,{toggle:!1}).toggle()})),Kt(Je);const Ge="dropdown",Qe="ArrowUp",tn="ArrowDown",en="click.bs.dropdown.data-api",nn="keydown.bs.dropdown.data-api",on="show",rn='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',sn=`${rn}.show`,an=".dropdown-menu",ln=Xt()?"top-end":"top-start",cn=Xt()?"top-start":"top-end",un=Xt()?"bottom-end":"bottom-start",dn=Xt()?"bottom-start":"bottom-end",hn=Xt()?"left-start":"right-start",pn=Xt()?"right-start":"left-start",mn={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},fn={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class gn extends we{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=Ee.next(this._element,an)[0]||Ee.prev(this._element,an)[0]||Ee.findOne(an,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return mn}static get DefaultType(){return fn}static get NAME(){return Ge}toggle(){return this._isShown()?this.hide():this.show()}show(){if($t(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!fe.trigger(this._element,"show.bs.dropdown",t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Yt);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(on),this._element.classList.add(on),fe.trigger(this._element,"shown.bs.dropdown",t)}}hide(){if($t(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!fe.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Yt);this._popper&&this._popper.destroy(),this._menu.classList.remove(on),this._element.classList.remove(on),this._element.setAttribute("aria-expanded","false"),be.removeDataAttribute(this._menu,"popper"),fe.trigger(this._element,"hidden.bs.dropdown",t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!Vt(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ge.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===i)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org/docs/v2/)");let t=this._element;"parent"===this._config.reference?t=this._parent:Vt(this._config.reference)?t=Rt(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=It(t,this._menu,e)}_isShown(){return this._menu.classList.contains(on)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return hn;if(t.classList.contains("dropstart"))return pn;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?cn:ln:e?dn:un}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(be.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,...Jt(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const n=Ee.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>Bt(t)));n.length&&Qt(n,e,t===tn,!n.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=Ee.find(sn);for(const n of e){const e=gn.getInstance(n);if(!e||!1===e._config.autoClose)continue;const i=t.composedPath(),o=i.includes(e._menu);if(i.includes(e._element)||"inside"===e._config.autoClose&&!o||"outside"===e._config.autoClose&&o)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const r={relatedTarget:e._element};"click"===t.type&&(r.clickEvent=t),e._completeHide(r)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),n="Escape"===t.key,i=[Qe,tn].includes(t.key);if(!i&&!n)return;if(e&&!n)return;t.preventDefault();const o=this.matches(rn)?this:Ee.prev(this,rn)[0]||Ee.next(this,rn)[0]||Ee.findOne(rn,t.delegateTarget.parentNode),r=gn.getOrCreateInstance(o);if(i)return t.stopPropagation(),r.show(),void r._selectMenuItem(t);r._isShown()&&(t.stopPropagation(),r.hide(),o.focus())}}fe.on(document,nn,rn,gn.dataApiKeydownHandler),fe.on(document,nn,an,gn.dataApiKeydownHandler),fe.on(document,en,gn.clearMenus),fe.on(document,"keyup.bs.dropdown.data-api",gn.clearMenus),fe.on(document,en,rn,(function(t){t.preventDefault(),gn.getOrCreateInstance(this).toggle()})),Kt(gn);const vn="backdrop",yn="show",bn="mousedown.bs.backdrop",_n={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},wn={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class kn extends _e{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return _n}static get DefaultType(){return wn}static get NAME(){return vn}show(t){if(!this._config.isVisible)return void Jt(t);this._append();const e=this._getElement();this._config.isAnimated&&zt(e),e.classList.add(yn),this._emulateAnimation((()=>{Jt(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(yn),this._emulateAnimation((()=>{this.dispose(),Jt(t)}))):Jt(t)}dispose(){this._isAppended&&(fe.off(this._element,bn),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=Rt(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),fe.on(t,bn,(()=>{Jt(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){Gt(t,this._getElement(),this._config.isAnimated)}}const En=".bs.focustrap",Dn="backward",Tn={autofocus:!0,trapElement:null},Sn={autofocus:"boolean",trapElement:"element"};class xn extends _e{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return Tn}static get DefaultType(){return Sn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),fe.off(document,En),fe.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),fe.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,fe.off(document,En))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const n=Ee.focusableChildren(e);0===n.length?e.focus():this._lastTabNavDirection===Dn?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Dn:"forward")}}const On=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",Cn=".sticky-top",Ln="padding-right",Mn="margin-right";class An{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,Ln,(e=>e+t)),this._setElementAttributes(On,Ln,(e=>e+t)),this._setElementAttributes(Cn,Mn,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,Ln),this._resetElementAttributes(On,Ln),this._resetElementAttributes(Cn,Mn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,n){const i=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+i)return;this._saveInitialAttribute(t,e);const o=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${n(Number.parseFloat(o))}px`)}))}_saveInitialAttribute(t,e){const n=t.style.getPropertyValue(e);n&&be.setDataAttribute(t,e,n)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const n=be.getDataAttribute(t,e);null!==n?(be.removeDataAttribute(t,e),t.style.setProperty(e,n)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(Vt(t))e(t);else for(const n of Ee.find(t,this._element))e(n)}}const In=".bs.modal",Nn="hidden.bs.modal",Pn="show.bs.modal",Fn="modal-open",jn="show",qn="modal-static",Hn={backdrop:!0,focus:!0,keyboard:!0},Vn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Rn extends we{constructor(t,e){super(t,e),this._dialog=Ee.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new An,this._addEventListeners()}static get Default(){return Hn}static get DefaultType(){return Vn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){if(this._isShown||this._isTransitioning)return;fe.trigger(this._element,Pn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Fn),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;fe.trigger(this._element,"hide.bs.modal").defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(jn),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated()))}dispose(){fe.off(window,In),fe.off(this._dialog,In),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new kn({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new xn({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=Ee.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),zt(this._element),this._element.classList.add(jn);this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,fe.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){fe.on(this._element,"keydown.dismiss.bs.modal",(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())})),fe.on(window,"resize.bs.modal",(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),fe.on(this._element,"mousedown.dismiss.bs.modal",(t=>{fe.one(this._element,"click.dismiss.bs.modal",(e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Fn),this._resetAdjustments(),this._scrollBar.reset(),fe.trigger(this._element,Nn)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(fe.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(qn)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(qn),this._queueCallback((()=>{this._element.classList.remove(qn),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),n=e>0;if(n&&!t){const t=Xt()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!n&&t){const t=Xt()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const n=Rn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===n[t])throw new TypeError(`No method named "${t}"`);n[t](e)}}))}}fe.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=Ee.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),fe.one(e,Pn,(t=>{t.defaultPrevented||fe.one(e,Nn,(()=>{Bt(this)&&this.focus()}))}));const n=Ee.findOne(".modal.show");n&&Rn.getInstance(n).hide();Rn.getOrCreateInstance(e).toggle(this)})),De(Rn),Kt(Rn);const Bn="show",$n="showing",Wn="hiding",Yn=".offcanvas.show",zn="hidePrevented.bs.offcanvas",Un="hidden.bs.offcanvas",Zn={backdrop:!0,keyboard:!0,scroll:!1},Xn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Kn extends we{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return Zn}static get DefaultType(){return Xn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){if(this._isShown)return;if(fe.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented)return;this._isShown=!0,this._backdrop.show(),this._config.scroll||(new An).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($n);this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Bn),this._element.classList.remove($n),fe.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0)}hide(){if(!this._isShown)return;if(fe.trigger(this._element,"hide.bs.offcanvas").defaultPrevented)return;this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Wn),this._backdrop.hide();this._queueCallback((()=>{this._element.classList.remove(Bn,Wn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new An).reset(),fe.trigger(this._element,Un)}),this._element,!0)}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new kn({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():fe.trigger(this._element,zn)}:null})}_initializeFocusTrap(){return new xn({trapElement:this._element})}_addEventListeners(){fe.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():fe.trigger(this._element,zn))}))}static jQueryInterface(t){return this.each((function(){const e=Kn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}fe.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=Ee.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),$t(this))return;fe.one(e,Un,(()=>{Bt(this)&&this.focus()}));const n=Ee.findOne(Yn);n&&n!==e&&Kn.getInstance(n).hide();Kn.getOrCreateInstance(e).toggle(this)})),fe.on(window,"load.bs.offcanvas.data-api",(()=>{for(const t of Ee.find(Yn))Kn.getOrCreateInstance(t).show()})),fe.on(window,"resize.bs.offcanvas",(()=>{for(const t of Ee.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Kn.getOrCreateInstance(t).hide()})),De(Kn),Kt(Kn);const Jn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Gn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Qn=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,ti=(t,e)=>{const n=t.nodeName.toLowerCase();return e.includes(n)?!Gn.has(n)||Boolean(Qn.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(n)))};const ei={allowList:Jn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},ni={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ii={entry:"(string|element|function|null)",selector:"(string|element)"};class oi extends _e{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return ei}static get DefaultType(){return ni}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,n]of Object.entries(this._config.content))this._setContent(t,n,e);const e=t.children[0],n=this._resolvePossibleFunction(this._config.extraClass);return n&&e.classList.add(...n.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,n]of Object.entries(t))super._typeCheckConfig({selector:e,entry:n},ii)}_setContent(t,e,n){const i=Ee.findOne(n,t);i&&((e=this._resolvePossibleFunction(e))?Vt(e)?this._putElementInTemplate(Rt(e),i):this._config.html?i.innerHTML=this._maybeSanitize(e):i.textContent=e:i.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,n){if(!t.length)return t;if(n&&"function"==typeof n)return n(t);const i=(new window.DOMParser).parseFromString(t,"text/html"),o=[].concat(...i.body.querySelectorAll("*"));for(const t of o){const n=t.nodeName.toLowerCase();if(!Object.keys(e).includes(n)){t.remove();continue}const i=[].concat(...t.attributes),o=[].concat(e["*"]||[],e[n]||[]);for(const e of i)ti(e,o)||t.removeAttribute(e.nodeName)}return i.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return Jt(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const ri=new Set(["sanitize","allowList","sanitizeFn"]),si="fade",ai="show",li=".modal",ci="hide.bs.modal",ui="hover",di="focus",hi={AUTO:"auto",TOP:"top",RIGHT:Xt()?"left":"right",BOTTOM:"bottom",LEFT:Xt()?"right":"left"},pi={allowList:Jn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},mi={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class fi extends we{constructor(t,e){if(void 0===i)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return pi}static get DefaultType(){return mi}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),fe.off(this._element.closest(li),ci,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=fe.trigger(this._element,this.constructor.eventName("show")),e=(Wt(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const n=this._getTipElement();this._element.setAttribute("aria-describedby",n.getAttribute("id"));const{container:i}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(i.append(n),fe.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(n),n.classList.add(ai),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.on(t,"mouseover",Yt);this._queueCallback((()=>{fe.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1}),this.tip,this._isAnimated())}hide(){if(!this._isShown())return;if(fe.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented)return;if(this._getTipElement().classList.remove(ai),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))fe.off(t,"mouseover",Yt);this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,this._isHovered=null;this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),fe.trigger(this._element,this.constructor.eventName("hidden")))}),this.tip,this._isAnimated())}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(si,ai),e.classList.add(`bs-${this.constructor.NAME}-auto`);const n=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",n),this._isAnimated()&&e.classList.add(si),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new oi({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(si)}_isShown(){return this.tip&&this.tip.classList.contains(ai)}_createPopper(t){const e=Jt(this._config.placement,[this,t,this._element]),n=hi[e.toUpperCase()];return It(this._element,t,this._getPopperConfig(n))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return Jt(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,...Jt(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)fe.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!(e._isShown()&&e._activeTrigger.click),e.toggle()}));else if("manual"!==e){const t=e===ui?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),n=e===ui?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");fe.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?di:ui]=!0,e._enter()})),fe.on(this._element,n,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?di:ui]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},fe.on(this._element.closest(li),ci,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=be.getDataAttributes(this._element);for(const t of Object.keys(e))ri.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:Rt(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,n]of Object.entries(this._config))this.constructor.Default[e]!==n&&(t[e]=n);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each((function(){const e=fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Kt(fi);const gi={...fi.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},vi={...fi.DefaultType,content:"(null|string|element|function)"};class yi extends fi{static get Default(){return gi}static get DefaultType(){return vi}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=yi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}Kt(yi);const bi="click.bs.scrollspy",_i="active",wi="[href]",ki={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Ei={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Di extends we{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ki}static get DefaultType(){return Ei}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=Rt(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map((t=>Number.parseFloat(t)))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(fe.off(this._config.target,bi),fe.on(this._config.target,bi,wi,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const n=this._rootElement||window,i=e.offsetTop-this._element.offsetTop;if(n.scrollTo)return void n.scrollTo({top:i,behavior:"smooth"});n.scrollTop=i}})))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),n=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},i=(this._rootElement||document.documentElement).scrollTop,o=i>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=i;for(const r of t){if(!r.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(r));continue}const t=r.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(o&&t){if(n(r),!i)return}else o||t||n(r)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=Ee.find(wi,this._config.target);for(const e of t){if(!e.hash||$t(e))continue;const t=Ee.findOne(decodeURI(e.hash),this._element);Bt(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(_i),this._activateParents(t),fe.trigger(this._element,"activate.bs.scrollspy",{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))Ee.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(_i);else for(const e of Ee.parents(t,".nav, .list-group"))for(const t of Ee.prev(e,".nav-link, .nav-item > .nav-link, .list-group-item"))t.classList.add(_i)}_clearActiveClass(t){t.classList.remove(_i);const e=Ee.find("[href].active",t);for(const t of e)t.classList.remove(_i)}static jQueryInterface(t){return this.each((function(){const e=Di.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}fe.on(window,"load.bs.scrollspy.data-api",(()=>{for(const t of Ee.find('[data-bs-spy="scroll"]'))Di.getOrCreateInstance(t)})),Kt(Di);const Ti="ArrowLeft",Si="ArrowRight",xi="ArrowUp",Oi="ArrowDown",Ci="Home",Li="End",Mi="active",Ai="fade",Ii="show",Ni=".dropdown-toggle",Pi='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Fi=`.nav-link:not(.dropdown-toggle), .list-group-item:not(.dropdown-toggle), [role="tab"]:not(.dropdown-toggle), ${Pi}`;class ji extends we{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),fe.on(this._element,"keydown.bs.tab",(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),n=e?fe.trigger(e,"hide.bs.tab",{relatedTarget:t}):null;fe.trigger(t,"show.bs.tab",{relatedTarget:e}).defaultPrevented||n&&n.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){if(!t)return;t.classList.add(Mi),this._activate(Ee.getElementFromSelector(t));this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),fe.trigger(t,"shown.bs.tab",{relatedTarget:e})):t.classList.add(Ii)}),t,t.classList.contains(Ai))}_deactivate(t,e){if(!t)return;t.classList.remove(Mi),t.blur(),this._deactivate(Ee.getElementFromSelector(t));this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),fe.trigger(t,"hidden.bs.tab",{relatedTarget:e})):t.classList.remove(Ii)}),t,t.classList.contains(Ai))}_keydown(t){if(![Ti,Si,xi,Oi,Ci,Li].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter((t=>!$t(t)));let n;if([Ci,Li].includes(t.key))n=e[t.key===Ci?0:e.length-1];else{const i=[Si,Oi].includes(t.key);n=Qt(e,t.target,i,!0)}n&&(n.focus({preventScroll:!0}),ji.getOrCreateInstance(n).show())}_getChildren(){return Ee.find(Fi,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),n=this._getOuterElement(t);t.setAttribute("aria-selected",e),n!==t&&this._setAttributeIfNotExists(n,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=Ee.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const n=this._getOuterElement(t);if(!n.classList.contains("dropdown"))return;const i=(t,i)=>{const o=Ee.findOne(t,n);o&&o.classList.toggle(i,e)};i(Ni,Mi),i(".dropdown-menu",Ii),n.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,n){t.hasAttribute(e)||t.setAttribute(e,n)}_elemIsActive(t){return t.classList.contains(Mi)}_getInnerElement(t){return t.matches(Fi)?t:Ee.findOne(Fi,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=ji.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}fe.on(document,"click.bs.tab",Pi,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),$t(this)||ji.getOrCreateInstance(this).show()})),fe.on(window,"load.bs.tab",(()=>{for(const t of Ee.find('.active[data-bs-toggle="tab"], .active[data-bs-toggle="pill"], .active[data-bs-toggle="list"]'))ji.getOrCreateInstance(t)})),Kt(ji);const qi="hide",Hi="show",Vi="showing",Ri={animation:"boolean",autohide:"boolean",delay:"number"},Bi={animation:!0,autohide:!0,delay:5e3};class $i extends we{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Bi}static get DefaultType(){return Ri}static get NAME(){return"toast"}show(){if(fe.trigger(this._element,"show.bs.toast").defaultPrevented)return;this._clearTimeout(),this._config.animation&&this._element.classList.add("fade");this._element.classList.remove(qi),zt(this._element),this._element.classList.add(Hi,Vi),this._queueCallback((()=>{this._element.classList.remove(Vi),fe.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation)}hide(){if(!this.isShown())return;if(fe.trigger(this._element,"hide.bs.toast").defaultPrevented)return;this._element.classList.add(Vi),this._queueCallback((()=>{this._element.classList.add(qi),this._element.classList.remove(Vi,Hi),fe.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(Hi),super.dispose()}isShown(){return this._element.classList.contains(Hi)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const n=t.relatedTarget;this._element===n||this._element.contains(n)||this._maybeScheduleHide()}_setListeners(){fe.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),fe.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),fe.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),fe.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=$i.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}De($i),Kt($i)},9997:function(t,e,n){"use strict";n.d(e,{A:function(){return i}});class i{static calculateContrastColor(t){"#"===t.slice(0,1)&&(t=t.slice(1)),3===t.length&&(t=t.split("").map((function(t){return t+t})).join(""));return(299*parseInt(t.substring(0,2),16)+587*parseInt(t.substring(2,4),16)+114*parseInt(t.substring(4,6),16))/1e3>=128?"#000000":"#ffffff"}}}},function(t){var e;e=4028,t(t.s=e)}]); \ No newline at end of file diff --git a/public/build/app.e6e198ed.js.LICENSE.txt b/public/build/app.5f84f245.js.LICENSE.txt similarity index 100% rename from public/build/app.e6e198ed.js.LICENSE.txt rename to public/build/app.5f84f245.js.LICENSE.txt diff --git a/public/build/app.e6e198ed.js b/public/build/app.e6e198ed.js deleted file mode 100644 index 026622c1c..000000000 --- a/public/build/app.e6e198ed.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! For license information please see app.e6e198ed.js.LICENSE.txt */ -(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[524],{424:function(t){window,t.exports=function(t){var e={};function n(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return t[i].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var o in t)n.d(i,o,function(e){return t[e]}.bind(null,o));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=4)}([function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var i=function(){function t(e,n,i){void 0===e&&(e=null),void 0===n&&(n=null),void 0===i&&(i="en-US"),this.dateInstance="object"==typeof n&&null!==n?n.parse(e instanceof t?e.clone().toJSDate():e):"string"==typeof n?t.parseDateTime(e,n,i):e?t.parseDateTime(e):t.parseDateTime(new Date),this.lang=i}return t.parseDateTime=function(e,n,i){if(void 0===n&&(n="YYYY-MM-DD"),void 0===i&&(i="en-US"),!e)return new Date(NaN);if(e instanceof Date)return new Date(e);if(e instanceof t)return e.clone().toJSDate();if(/^-?\d{10,}$/.test(e))return t.getDateZeroTime(new Date(Number(e)));if("string"==typeof e){for(var o=[],r=null;null!=(r=t.regex.exec(n));)"\\"!==r[1]&&o.push(r);if(o.length){var s={year:null,month:null,shortMonth:null,longMonth:null,day:null,value:""};o[0].index>0&&(s.value+=".*?");for(var a=0,l=Object.entries(o);at.getTime()&&this.timestamp()=t.getTime()&&this.timestamp()t.getTime()&&this.timestamp()<=e.getTime();case"[]":return this.timestamp()>=t.getTime()&&this.timestamp()<=e.getTime()}},t.prototype.isBefore=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":return t.getTime()>this.getTime();case"day":case"days":return new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()>new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime();case"month":case"months":return new Date(t.getFullYear(),t.getMonth(),1).getTime()>new Date(this.getFullYear(),this.getMonth(),1).getTime();case"year":case"years":return t.getFullYear()>this.getFullYear()}throw new Error("isBefore: Invalid unit!")},t.prototype.isSameOrBefore=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":return t.getTime()>=this.getTime();case"day":case"days":return new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime()>=new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime();case"month":case"months":return new Date(t.getFullYear(),t.getMonth(),1).getTime()>=new Date(this.getFullYear(),this.getMonth(),1).getTime()}throw new Error("isSameOrBefore: Invalid unit!")},t.prototype.isAfter=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":return this.getTime()>t.getTime();case"day":case"days":return new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime()>new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime();case"month":case"months":return new Date(this.getFullYear(),this.getMonth(),1).getTime()>new Date(t.getFullYear(),t.getMonth(),1).getTime();case"year":case"years":return this.getFullYear()>t.getFullYear()}throw new Error("isAfter: Invalid unit!")},t.prototype.isSameOrAfter=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":return this.getTime()>=t.getTime();case"day":case"days":return new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime()>=new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime();case"month":case"months":return new Date(this.getFullYear(),this.getMonth(),1).getTime()>=new Date(t.getFullYear(),t.getMonth(),1).getTime()}throw new Error("isSameOrAfter: Invalid unit!")},t.prototype.isSame=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":return this.getTime()===t.getTime();case"day":case"days":return new Date(this.getFullYear(),this.getMonth(),this.getDate()).getTime()===new Date(t.getFullYear(),t.getMonth(),t.getDate()).getTime();case"month":case"months":return new Date(this.getFullYear(),this.getMonth(),1).getTime()===new Date(t.getFullYear(),t.getMonth(),1).getTime()}throw new Error("isSame: Invalid unit!")},t.prototype.add=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":this.setSeconds(this.getSeconds()+t);break;case"day":case"days":this.setDate(this.getDate()+t);break;case"month":case"months":this.setMonth(this.getMonth()+t)}return this},t.prototype.subtract=function(t,e){switch(void 0===e&&(e="seconds"),e){case"second":case"seconds":this.setSeconds(this.getSeconds()-t);break;case"day":case"days":this.setDate(this.getDate()-t);break;case"month":case"months":this.setMonth(this.getMonth()-t)}return this},t.prototype.diff=function(t,e){switch(void 0===e&&(e="seconds"),e){default:case"second":case"seconds":return this.getTime()-t.getTime();case"day":case"days":return Math.round((this.timestamp()-t.getTime())/864e5);case"month":case"months":}},t.prototype.format=function(e,n){if(void 0===n&&(n="en-US"),"object"==typeof e)return e.output(this.clone().toJSDate());for(var i="",o=[],r=null;null!=(r=t.regex.exec(e));)"\\"!==r[1]&&o.push(r);if(o.length){o[0].index>0&&(i+=e.substring(0,o[0].index));for(var s=0,a=Object.entries(o);s1&&n.isAfter(e)&&n.setMonth(n.getMonth()-(this.options.numberOfMonths-1)),this.calendars[0]=n.clone()):(e.setDate(1),this.calendars[0]=e.clone())}},e.prototype.bindEvents=function(){document.addEventListener("click",this.onClick.bind(this),!0),this.ui=document.createElement("div"),this.ui.className=l.litepicker,this.ui.style.display="none",this.ui.addEventListener("mouseenter",this.onMouseEnter.bind(this),!0),this.ui.addEventListener("mouseleave",this.onMouseLeave.bind(this),!1),this.options.autoRefresh?(this.options.element instanceof HTMLElement&&this.options.element.addEventListener("keyup",this.onInput.bind(this),!0),this.options.elementEnd instanceof HTMLElement&&this.options.elementEnd.addEventListener("keyup",this.onInput.bind(this),!0)):(this.options.element instanceof HTMLElement&&this.options.element.addEventListener("change",this.onInput.bind(this),!0),this.options.elementEnd instanceof HTMLElement&&this.options.elementEnd.addEventListener("change",this.onInput.bind(this),!0)),this.options.parentEl?this.options.parentEl instanceof HTMLElement?this.options.parentEl.appendChild(this.ui):document.querySelector(this.options.parentEl).appendChild(this.ui):this.options.inlineMode?this.options.element instanceof HTMLInputElement?this.options.element.parentNode.appendChild(this.ui):this.options.element.appendChild(this.ui):document.body.appendChild(this.ui),this.updateInput(),this.init(),"function"==typeof this.options.setup&&this.options.setup.call(this,this),this.render(),this.options.inlineMode&&this.show()},e.prototype.updateInput=function(){if(this.options.element instanceof HTMLInputElement){var t=this.options.startDate,e=this.options.endDate;if(this.options.singleMode&&t)this.options.element.value=t.format(this.options.format,this.options.lang);else if(!this.options.singleMode&&t&&e){var n=t.format(this.options.format,this.options.lang),i=e.format(this.options.format,this.options.lang);this.options.elementEnd instanceof HTMLInputElement?(this.options.element.value=n,this.options.elementEnd.value=i):this.options.element.value=""+n+this.options.delimiter+i}t||e||(this.options.element.value="",this.options.elementEnd instanceof HTMLInputElement&&(this.options.elementEnd.value=""))}},e.prototype.isSamePicker=function(t){return t.closest("."+l.litepicker)===this.ui},e.prototype.shouldShown=function(t){return!t.disabled&&(t===this.options.element||this.options.elementEnd&&t===this.options.elementEnd)},e.prototype.shouldResetDatePicked=function(){return this.options.singleMode||2===this.datePicked.length},e.prototype.shouldSwapDatePicked=function(){return 2===this.datePicked.length&&this.datePicked[0].getTime()>this.datePicked[1].getTime()},e.prototype.shouldCheckLockDays=function(){return this.options.disallowLockDaysInRange&&2===this.datePicked.length},e.prototype.onClick=function(t){var e=t.target;if(t.target.shadowRoot&&(e=t.composedPath()[0]),e&&this.ui)if(this.shouldShown(e))this.show(e);else if(e.closest("."+l.litepicker)||!this.isShowning()){if(this.isSamePicker(e))if(this.emit("before:click",e),this.preventClick)this.preventClick=!1;else{if(e.classList.contains(l.dayItem)){if(t.preventDefault(),e.classList.contains(l.isLocked))return;if(this.shouldResetDatePicked()&&(this.datePicked.length=0),this.datePicked[this.datePicked.length]=new a.DateTime(e.dataset.time),this.shouldSwapDatePicked()){var n=this.datePicked[1].clone();this.datePicked[1]=this.datePicked[0].clone(),this.datePicked[0]=n.clone()}return this.shouldCheckLockDays()&&c.rangeIsLocked(this.datePicked,this.options)&&(this.emit("error:range",this.datePicked),this.datePicked.length=0),this.render(),this.emit.apply(this,r(["preselect"],r(this.datePicked).map((function(t){return t.clone()})))),void(this.options.autoApply&&(this.options.singleMode&&this.datePicked.length?(this.setDate(this.datePicked[0]),this.hide()):this.options.singleMode||2!==this.datePicked.length||(this.setDateRange(this.datePicked[0],this.datePicked[1]),this.hide())))}if(e.classList.contains(l.buttonPreviousMonth)){t.preventDefault();var i=0,o=this.options.switchingMonths||this.options.numberOfMonths;if(this.options.splitView){var s=e.closest("."+l.monthItem);i=c.findNestedMonthItem(s),o=1}return this.calendars[i].setMonth(this.calendars[i].getMonth()-o),this.gotoDate(this.calendars[i],i),void this.emit("change:month",this.calendars[i],i)}if(e.classList.contains(l.buttonNextMonth))return t.preventDefault(),i=0,o=this.options.switchingMonths||this.options.numberOfMonths,this.options.splitView&&(s=e.closest("."+l.monthItem),i=c.findNestedMonthItem(s),o=1),this.calendars[i].setMonth(this.calendars[i].getMonth()+o),this.gotoDate(this.calendars[i],i),void this.emit("change:month",this.calendars[i],i);e.classList.contains(l.buttonCancel)&&(t.preventDefault(),this.hide(),this.emit("button:cancel")),e.classList.contains(l.buttonApply)&&(t.preventDefault(),this.options.singleMode&&this.datePicked.length?this.setDate(this.datePicked[0]):this.options.singleMode||2!==this.datePicked.length||this.setDateRange(this.datePicked[0],this.datePicked[1]),this.hide(),this.emit("button:apply",this.options.startDate,this.options.endDate))}}else this.hide()},e.prototype.showTooltip=function(t,e){var n=this.ui.querySelector("."+l.containerTooltip);n.style.visibility="visible",n.innerHTML=e;var i=this.ui.getBoundingClientRect(),o=n.getBoundingClientRect(),r=t.getBoundingClientRect(),s=r.top,a=r.left;if(this.options.inlineMode&&this.options.parentEl){var c=this.ui.parentNode.getBoundingClientRect();s-=c.top,a-=c.left}else s-=i.top,a-=i.left;s-=o.height,a-=o.width/2,a+=r.width/2,n.style.top=s+"px",n.style.left=a+"px",this.emit("tooltip",n,t)},e.prototype.hideTooltip=function(){this.ui.querySelector("."+l.containerTooltip).style.visibility="hidden"},e.prototype.shouldAllowMouseEnter=function(t){return!this.options.singleMode&&!t.classList.contains(l.isLocked)},e.prototype.shouldAllowRepick=function(){return this.options.elementEnd&&this.options.allowRepick&&this.options.startDate&&this.options.endDate},e.prototype.isDayItem=function(t){return t.classList.contains(l.dayItem)},e.prototype.onMouseEnter=function(t){var e=this,n=t.target;if(this.isDayItem(n)&&this.shouldAllowMouseEnter(n)){if(this.shouldAllowRepick()&&(this.triggerElement===this.options.element?this.datePicked[0]=this.options.endDate.clone():this.triggerElement===this.options.elementEnd&&(this.datePicked[0]=this.options.startDate.clone())),1!==this.datePicked.length)return;var i=this.ui.querySelector("."+l.dayItem+'[data-time="'+this.datePicked[0].getTime()+'"]'),o=this.datePicked[0].clone(),r=new a.DateTime(n.dataset.time),s=!1;if(o.getTime()>r.getTime()){var c=o.clone();o=r.clone(),r=c.clone(),s=!0}if(Array.prototype.slice.call(this.ui.querySelectorAll("."+l.dayItem)).forEach((function(t){var n=new a.DateTime(t.dataset.time),i=e.renderDay(n);n.isBetween(o,r)&&i.classList.add(l.isInRange),t.className=i.className})),n.classList.add(l.isEndDate),s?(i&&i.classList.add(l.isFlipped),n.classList.add(l.isFlipped)):(i&&i.classList.remove(l.isFlipped),n.classList.remove(l.isFlipped)),this.options.showTooltip){var u=r.diff(o,"day")+1;if("function"==typeof this.options.tooltipNumber&&(u=this.options.tooltipNumber.call(this,u)),u>0){var d=this.pluralSelector(u),h=u+" "+(this.options.tooltipText[d]?this.options.tooltipText[d]:"["+d+"]");this.showTooltip(n,h);var p=window.navigator.userAgent,m=/(iphone|ipad)/i.test(p),f=/OS 1([0-2])/i.test(p);m&&f&&n.dispatchEvent(new Event("click"))}else this.hideTooltip()}}},e.prototype.onMouseLeave=function(t){t.target,this.options.allowRepick&&(!this.options.allowRepick||this.options.startDate||this.options.endDate)&&(this.datePicked.length=0,this.render())},e.prototype.onInput=function(t){var e=this.parseInput(),n=e[0],i=e[1],o=this.options.format;if(this.options.elementEnd?n instanceof a.DateTime&&i instanceof a.DateTime&&n.format(o)===this.options.element.value&&i.format(o)===this.options.elementEnd.value:this.options.singleMode?n instanceof a.DateTime&&n.format(o)===this.options.element.value:n instanceof a.DateTime&&i instanceof a.DateTime&&""+n.format(o)+this.options.delimiter+i.format(o)===this.options.element.value){if(i&&n.getTime()>i.getTime()){var r=n.clone();n=i.clone(),i=r.clone()}this.options.startDate=new a.DateTime(n,this.options.format,this.options.lang),i&&(this.options.endDate=new a.DateTime(i,this.options.format,this.options.lang)),this.updateInput(),this.render();var s=n.clone(),l=0;(this.options.elementEnd?n.format(o)===t.target.value:t.target.value.startsWith(n.format(o)))||(s=i.clone(),l=this.options.numberOfMonths-1),this.emit("selected",this.getStartDate(),this.getEndDate()),this.gotoDate(s,l)}},e}(s.Calendar);e.Litepicker=u},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.findNestedMonthItem=function(t){for(var e=t.parentNode.childNodes,n=0;ny&&((p=document.createElement("option")).value=String(t.getFullYear()),p.text=String(t.getFullYear()),p.selected=!0,p.disabled=!0,g.appendChild(p)),h=y;h>=v;h-=1){p=document.createElement("option");var b=new s.DateTime(new Date(h,0,1,0,0,0));p.value=String(h),p.text=String(h),p.disabled=this.options.minDate&&b.isBefore(new s.DateTime(this.options.minDate),"year")||this.options.maxDate&&b.isAfter(new s.DateTime(this.options.maxDate),"year"),p.selected=t.getFullYear()===h,g.appendChild(p)}if(t.getFullYear()W
");for(var T=1;T<=7;T+=1){var S=3+this.options.firstDay+T,x=document.createElement("div");x.innerHTML=this.weekdayName(S),x.title=this.weekdayName(S,"long"),D.appendChild(x)}var O=document.createElement("div");O.className=a.containerDays;var C=this.calcSkipDays(i);this.options.showWeekNumbers&&C&&O.appendChild(this.renderWeekNumber(i));for(var L=0;L1&&1===this.datePicked.length){var o=this.options.minDays-1,r=this.datePicked[0].clone().subtract(o,"day"),c=this.datePicked[0].clone().add(o,"day");t.isBetween(r,this.datePicked[0],"(]")&&e.classList.add(a.isLocked),t.isBetween(this.datePicked[0],c,"[)")&&e.classList.add(a.isLocked)}if(this.options.maxDays&&1===this.datePicked.length){var u=this.options.maxDays;r=this.datePicked[0].clone().subtract(u,"day"),c=this.datePicked[0].clone().add(u,"day"),t.isSameOrBefore(r)&&e.classList.add(a.isLocked),t.isSameOrAfter(c)&&e.classList.add(a.isLocked)}return this.options.selectForward&&1===this.datePicked.length&&t.isBefore(this.datePicked[0])&&e.classList.add(a.isLocked),this.options.selectBackward&&1===this.datePicked.length&&t.isAfter(this.datePicked[0])&&e.classList.add(a.isLocked),l.dateIsLocked(t,this.options,this.datePicked)&&e.classList.add(a.isLocked),this.options.highlightedDays.length&&this.options.highlightedDays.filter((function(e){return e instanceof Array?t.isBetween(e[0],e[1],"[]"):e.isSame(t,"day")})).length&&e.classList.add(a.isHighlighted),e.tabIndex=e.classList.contains("is-locked")?-1:0,this.emit("render:day",e,t),e},e.prototype.renderFooter=function(){var t=document.createElement("div");if(t.className=a.containerFooter,this.options.footerHTML?t.innerHTML=this.options.footerHTML:t.innerHTML='\n \n \n \n ",this.options.singleMode){if(1===this.datePicked.length){var e=this.datePicked[0].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=e}}else if(1===this.datePicked.length&&t.querySelector("."+a.buttonApply).setAttribute("disabled",""),2===this.datePicked.length){e=this.datePicked[0].format(this.options.format,this.options.lang);var n=this.datePicked[1].format(this.options.format,this.options.lang);t.querySelector("."+a.previewDateRange).innerHTML=""+e+this.options.delimiter+n}return this.emit("render:footer",t),t},e.prototype.renderWeekNumber=function(t){var e=document.createElement("div"),n=t.getWeek(this.options.firstDay);return e.className=a.weekNumber,e.innerHTML=53===n&&0===t.getMonth()?"53 / 1":n,e},e.prototype.renderTooltip=function(){var t=document.createElement("div");return t.className=a.containerTooltip,t},e.prototype.weekdayName=function(t,e){return void 0===e&&(e="short"),new Date(1970,0,t,12,0,0,0).toLocaleString(this.options.lang,{weekday:e})},e.prototype.calcSkipDays=function(t){var e=t.getDay()-this.options.firstDay;return e<0&&(e+=7),e},e}(r.LPCore);e.Calendar=c},function(t,e,n){"use strict";var i,o=this&&this.__extends||(i=function(t,e){return(i=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])})(t,e)},function(t,e){function n(){this.constructor=t}i(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}),r=this&&this.__assign||function(){return(r=Object.assign||function(t){for(var e,n=1,i=arguments.length;n',nextMonth:'',reset:'\n \n \n '},tooltipText:{one:"day",other:"days"}},n.options=r(r({},n.options),e.element.dataset),Object.keys(n.options).forEach((function(t){"true"!==n.options[t]&&"false"!==n.options[t]||(n.options[t]="true"===n.options[t])}));var i=r(r({},n.options.dropdowns),e.dropdowns),o=r(r({},n.options.buttonText),e.buttonText),s=r(r({},n.options.tooltipText),e.tooltipText);n.options=r(r({},n.options),e),n.options.dropdowns=r({},i),n.options.buttonText=r({},o),n.options.tooltipText=r({},s),n.options.elementEnd||(n.options.allowRepick=!1),n.options.lockDays.length&&(n.options.lockDays=a.DateTime.convertArray(n.options.lockDays,n.options.lockDaysFormat)),n.options.highlightedDays.length&&(n.options.highlightedDays=a.DateTime.convertArray(n.options.highlightedDays,n.options.highlightedDaysFormat));var l=n.parseInput(),c=l[0],u=l[1];n.options.startDate&&(n.options.singleMode||n.options.endDate)&&(c=new a.DateTime(n.options.startDate,n.options.format,n.options.lang)),c&&n.options.endDate&&(u=new a.DateTime(n.options.endDate,n.options.format,n.options.lang)),c instanceof a.DateTime&&!isNaN(c.getTime())&&(n.options.startDate=c),n.options.startDate&&u instanceof a.DateTime&&!isNaN(u.getTime())&&(n.options.endDate=u),!n.options.singleMode||n.options.startDate instanceof a.DateTime||(n.options.startDate=null),n.options.singleMode||n.options.startDate instanceof a.DateTime&&n.options.endDate instanceof a.DateTime||(n.options.startDate=null,n.options.endDate=null);for(var d=0;dwindow.innerHeight,c=e.top+r-n.height>=n.height;l&&c&&(s=e.top+r-n.height)}if(/left|right/.test(i[0])||i[1]&&"auto"!==i[1]&&/left|right/.test(i[1]))a=/left|right/.test(i[0])?e[i[0]]+o:e[i[1]]+o,"right"!==i[0]&&"right"!==i[1]||(a-=n.width);else{a=e.left+o,l=e.left+n.width>window.innerWidth;var u=e.right+o-n.width>=0;l&&u&&(a=e.right+o-n.width)}return{left:a,top:s}},e}(s.EventEmitter);e.LPCore=c},function(t,e,n){"use strict";var i,o="object"==typeof Reflect?Reflect:null,r=o&&"function"==typeof o.apply?o.apply:function(t,e,n){return Function.prototype.apply.call(t,e,n)};i=o&&"function"==typeof o.ownKeys?o.ownKeys:Object.getOwnPropertySymbols?function(t){return Object.getOwnPropertyNames(t).concat(Object.getOwnPropertySymbols(t))}:function(t){return Object.getOwnPropertyNames(t)};var s=Number.isNaN||function(t){return t!=t};function a(){a.init.call(this)}t.exports=a,a.EventEmitter=a,a.prototype._events=void 0,a.prototype._eventsCount=0,a.prototype._maxListeners=void 0;var l=10;function c(t){return void 0===t._maxListeners?a.defaultMaxListeners:t._maxListeners}function u(t,e,n,i){var o,r,s,a;if("function"!=typeof n)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof n);if(void 0===(r=t._events)?(r=t._events=Object.create(null),t._eventsCount=0):(void 0!==r.newListener&&(t.emit("newListener",e,n.listener?n.listener:n),r=t._events),s=r[e]),void 0===s)s=r[e]=n,++t._eventsCount;else if("function"==typeof s?s=r[e]=i?[n,s]:[s,n]:i?s.unshift(n):s.push(n),(o=c(t))>0&&s.length>o&&!s.warned){s.warned=!0;var l=new Error("Possible EventEmitter memory leak detected. "+s.length+" "+String(e)+" listeners added. Use emitter.setMaxListeners() to increase limit");l.name="MaxListenersExceededWarning",l.emitter=t,l.type=e,l.count=s.length,a=l,console&&console.warn&&console.warn(a)}return t}function d(){for(var t=[],e=0;e0&&(s=e[0]),s instanceof Error)throw s;var a=new Error("Unhandled error."+(s?" ("+s.message+")":""));throw a.context=s,a}var l=o[t];if(void 0===l)return!1;if("function"==typeof l)r(l,this,e);else{var c=l.length,u=f(l,c);for(n=0;n=0;r--)if(n[r]===e||n[r].listener===e){s=n[r].listener,o=r;break}if(o<0)return this;0===o?n.shift():function(t,e){for(;e+1=0;i--)this.removeListener(t,e[i]);return this},a.prototype.listeners=function(t){return p(this,t,!0)},a.prototype.rawListeners=function(t){return p(this,t,!1)},a.listenerCount=function(t,e){return"function"==typeof t.listenerCount?t.listenerCount(e):m.call(t,e)},a.prototype.listenerCount=m,a.prototype.eventNames=function(){return this._eventsCount>0?i(this._events):[]}},function(t,e,n){(e=n(9)(!1)).push([t.i,':root{--litepicker-container-months-color-bg: #fff;--litepicker-container-months-box-shadow-color: #ddd;--litepicker-footer-color-bg: #fafafa;--litepicker-footer-box-shadow-color: #ddd;--litepicker-tooltip-color-bg: #fff;--litepicker-month-header-color: #333;--litepicker-button-prev-month-color: #9e9e9e;--litepicker-button-next-month-color: #9e9e9e;--litepicker-button-prev-month-color-hover: #2196f3;--litepicker-button-next-month-color-hover: #2196f3;--litepicker-month-width: calc(var(--litepicker-day-width) * 7);--litepicker-month-weekday-color: #9e9e9e;--litepicker-month-week-number-color: #9e9e9e;--litepicker-day-width: 38px;--litepicker-day-color: #333;--litepicker-day-color-hover: #2196f3;--litepicker-is-today-color: #f44336;--litepicker-is-in-range-color: #bbdefb;--litepicker-is-locked-color: #9e9e9e;--litepicker-is-start-color: #fff;--litepicker-is-start-color-bg: #2196f3;--litepicker-is-end-color: #fff;--litepicker-is-end-color-bg: #2196f3;--litepicker-button-cancel-color: #fff;--litepicker-button-cancel-color-bg: #9e9e9e;--litepicker-button-apply-color: #fff;--litepicker-button-apply-color-bg: #2196f3;--litepicker-button-reset-color: #909090;--litepicker-button-reset-color-hover: #2196f3;--litepicker-highlighted-day-color: #333;--litepicker-highlighted-day-color-bg: #ffeb3b}.show-week-numbers{--litepicker-month-width: calc(var(--litepicker-day-width) * 8)}.litepicker{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;font-size:0.8em;display:none}.litepicker button{border:none;background:none}.litepicker .container__main{display:-webkit-box;display:-ms-flexbox;display:flex}.litepicker .container__months{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background-color:var(--litepicker-container-months-color-bg);border-radius:5px;-webkit-box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);box-shadow:0 0 5px var(--litepicker-container-months-box-shadow-color);width:calc(var(--litepicker-month-width) + 10px);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months.columns-2{width:calc((var(--litepicker-month-width) * 2) + 20px)}.litepicker .container__months.columns-3{width:calc((var(--litepicker-month-width) * 3) + 30px)}.litepicker .container__months.columns-4{width:calc((var(--litepicker-month-width) * 4) + 40px)}.litepicker .container__months.split-view .month-item-header .button-previous-month,.litepicker .container__months.split-view .month-item-header .button-next-month{visibility:visible}.litepicker .container__months .month-item{padding:5px;width:var(--litepicker-month-width);-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__months .month-item-header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;font-weight:500;padding:10px 5px;text-align:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:var(--litepicker-month-header-color)}.litepicker .container__months .month-item-header div{-webkit-box-flex:1;-ms-flex:1;flex:1}.litepicker .container__months .month-item-header div>.month-item-name{margin-right:5px}.litepicker .container__months .month-item-header div>.month-item-year{padding:0}.litepicker .container__months .month-item-header .reset-button{color:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button>svg{fill:var(--litepicker-button-reset-color)}.litepicker .container__months .month-item-header .reset-button *{pointer-events:none}.litepicker .container__months .month-item-header .reset-button:hover{color:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .reset-button:hover>svg{fill:var(--litepicker-button-reset-color-hover)}.litepicker .container__months .month-item-header .button-previous-month,.litepicker .container__months .month-item-header .button-next-month{visibility:hidden;text-decoration:none;padding:3px 5px;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__months .month-item-header .button-previous-month *,.litepicker .container__months .month-item-header .button-next-month *{pointer-events:none}.litepicker .container__months .month-item-header .button-previous-month{color:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month>svg,.litepicker .container__months .month-item-header .button-previous-month>img{fill:var(--litepicker-button-prev-month-color)}.litepicker .container__months .month-item-header .button-previous-month:hover{color:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-previous-month:hover>svg{fill:var(--litepicker-button-prev-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month{color:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month>svg,.litepicker .container__months .month-item-header .button-next-month>img{fill:var(--litepicker-button-next-month-color)}.litepicker .container__months .month-item-header .button-next-month:hover{color:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-header .button-next-month:hover>svg{fill:var(--litepicker-button-next-month-color-hover)}.litepicker .container__months .month-item-weekdays-row{display:-webkit-box;display:-ms-flexbox;display:flex;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;color:var(--litepicker-month-weekday-color)}.litepicker .container__months .month-item-weekdays-row>div{padding:5px 0;font-size:85%;-webkit-box-flex:1;-ms-flex:1;flex:1;width:var(--litepicker-day-width);text-align:center}.litepicker .container__months .month-item:first-child .button-previous-month{visibility:visible}.litepicker .container__months .month-item:last-child .button-next-month{visibility:visible}.litepicker .container__months .month-item.no-previous-month .button-previous-month{visibility:hidden}.litepicker .container__months .month-item.no-next-month .button-next-month{visibility:hidden}.litepicker .container__days{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;justify-self:center;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;text-align:center;-webkit-box-sizing:content-box;box-sizing:content-box}.litepicker .container__days>div,.litepicker .container__days>a{padding:5px 0;width:var(--litepicker-day-width)}.litepicker .container__days .day-item{color:var(--litepicker-day-color);text-align:center;text-decoration:none;border-radius:3px;-webkit-transition:color 0.3s, border 0.3s;transition:color 0.3s, border 0.3s;cursor:default}.litepicker .container__days .day-item:hover{color:var(--litepicker-day-color-hover);-webkit-box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover);box-shadow:inset 0 0 0 1px var(--litepicker-day-color-hover)}.litepicker .container__days .day-item.is-today{color:var(--litepicker-is-today-color)}.litepicker .container__days .day-item.is-locked{color:var(--litepicker-is-locked-color)}.litepicker .container__days .day-item.is-locked:hover{color:var(--litepicker-is-locked-color);-webkit-box-shadow:none;box-shadow:none;cursor:default}.litepicker .container__days .day-item.is-in-range{background-color:var(--litepicker-is-in-range-color);border-radius:0}.litepicker .container__days .day-item.is-start-date{color:var(--litepicker-is-start-color);background-color:var(--litepicker-is-start-color-bg);border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-flipped{border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date{color:var(--litepicker-is-end-color);background-color:var(--litepicker-is-end-color-bg);border-top-left-radius:0;border-bottom-left-radius:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-end-date.is-flipped{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:0;border-bottom-right-radius:0}.litepicker .container__days .day-item.is-start-date.is-end-date{border-top-left-radius:5px;border-bottom-left-radius:5px;border-top-right-radius:5px;border-bottom-right-radius:5px}.litepicker .container__days .day-item.is-highlighted{color:var(--litepicker-highlighted-day-color);background-color:var(--litepicker-highlighted-day-color-bg)}.litepicker .container__days .week-number{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:var(--litepicker-month-week-number-color);font-size:85%}.litepicker .container__footer{text-align:right;padding:10px 5px;margin:0 5px;background-color:var(--litepicker-footer-color-bg);-webkit-box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);box-shadow:inset 0px 3px 3px 0px var(--litepicker-footer-box-shadow-color);border-bottom-left-radius:5px;border-bottom-right-radius:5px}.litepicker .container__footer .preview-date-range{margin-right:10px;font-size:90%}.litepicker .container__footer .button-cancel{background-color:var(--litepicker-button-cancel-color-bg);color:var(--litepicker-button-cancel-color);border:0;padding:3px 7px 4px;border-radius:3px}.litepicker .container__footer .button-cancel *{pointer-events:none}.litepicker .container__footer .button-apply{background-color:var(--litepicker-button-apply-color-bg);color:var(--litepicker-button-apply-color);border:0;padding:3px 7px 4px;border-radius:3px;margin-left:10px;margin-right:10px}.litepicker .container__footer .button-apply:disabled{opacity:0.7}.litepicker .container__footer .button-apply *{pointer-events:none}.litepicker .container__tooltip{position:absolute;margin-top:-4px;padding:4px 8px;border-radius:4px;background-color:var(--litepicker-tooltip-color-bg);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.25);box-shadow:0 1px 3px rgba(0,0,0,0.25);white-space:nowrap;font-size:11px;pointer-events:none;visibility:hidden}.litepicker .container__tooltip:before{position:absolute;bottom:-5px;left:calc(50% - 5px);border-top:5px solid rgba(0,0,0,0.12);border-right:5px solid transparent;border-left:5px solid transparent;content:""}.litepicker .container__tooltip:after{position:absolute;bottom:-4px;left:calc(50% - 4px);border-top:4px solid var(--litepicker-tooltip-color-bg);border-right:4px solid transparent;border-left:4px solid transparent;content:""}\n',""]),e.locals={showWeekNumbers:"show-week-numbers",litepicker:"litepicker",containerMain:"container__main",containerMonths:"container__months",columns2:"columns-2",columns3:"columns-3",columns4:"columns-4",splitView:"split-view",monthItemHeader:"month-item-header",buttonPreviousMonth:"button-previous-month",buttonNextMonth:"button-next-month",monthItem:"month-item",monthItemName:"month-item-name",monthItemYear:"month-item-year",resetButton:"reset-button",monthItemWeekdaysRow:"month-item-weekdays-row",noPreviousMonth:"no-previous-month",noNextMonth:"no-next-month",containerDays:"container__days",dayItem:"day-item",isToday:"is-today",isLocked:"is-locked",isInRange:"is-in-range",isStartDate:"is-start-date",isFlipped:"is-flipped",isEndDate:"is-end-date",isHighlighted:"is-highlighted",weekNumber:"week-number",containerFooter:"container__footer",previewDateRange:"preview-date-range",buttonCancel:"button-cancel",buttonApply:"button-apply",containerTooltip:"container__tooltip"},t.exports=e},function(t,e,n){"use strict";t.exports=function(t){var e=[];return e.toString=function(){return this.map((function(e){var n=function(t,e){var n,i,o,r=t[1]||"",s=t[3];if(!s)return r;if(e&&"function"==typeof btoa){var a=(n=s,i=btoa(unescape(encodeURIComponent(JSON.stringify(n)))),o="sourceMappingURL=data:application/json;charset=utf-8;base64,".concat(i),"/*# ".concat(o," */")),l=s.sources.map((function(t){return"/*# sourceURL=".concat(s.sourceRoot||"").concat(t," */")}));return[r].concat(l).concat([a]).join("\n")}return[r].join("\n")}(e,t);return e[2]?"@media ".concat(e[2]," {").concat(n,"}"):n})).join("")},e.i=function(t,n,i){"string"==typeof t&&(t=[[null,t,""]]);var o={};if(i)for(var r=0;rthis.options.endDate.getTime()&&(this.options.endDate=this.options.startDate.clone(),this.options.startDate=new o.DateTime(t,this.options.format,this.options.lang)),this.updateInput())},r.Litepicker.prototype.setDateRange=function(t,e,n){void 0===n&&(n=!1),this.triggerElement=void 0;var i=new o.DateTime(t,this.options.format,this.options.lang),r=new o.DateTime(e,this.options.format,this.options.lang);(this.options.disallowLockDaysInRange?s.rangeIsLocked([i,r],this.options):s.dateIsLocked(i,this.options,[i,r])||s.dateIsLocked(r,this.options,[i,r]))&&!n?this.emit("error:range",[i,r]):(this.setStartDate(i),this.setEndDate(r),this.options.inlineMode&&this.render(),this.updateInput(),this.emit("selected",this.getStartDate(),this.getEndDate()))},r.Litepicker.prototype.gotoDate=function(t,e){void 0===e&&(e=0);var n=new o.DateTime(t);n.setDate(1),this.calendars[e]=n.clone(),this.render()},r.Litepicker.prototype.setLockDays=function(t){this.options.lockDays=o.DateTime.convertArray(t,this.options.lockDaysFormat),this.render()},r.Litepicker.prototype.setHighlightedDays=function(t){this.options.highlightedDays=o.DateTime.convertArray(t,this.options.highlightedDaysFormat),this.render()},r.Litepicker.prototype.setOptions=function(t){delete t.element,delete t.elementEnd,delete t.parentEl,t.startDate&&(t.startDate=new o.DateTime(t.startDate,this.options.format,this.options.lang)),t.endDate&&(t.endDate=new o.DateTime(t.endDate,this.options.format,this.options.lang));var e=i(i({},this.options.dropdowns),t.dropdowns),n=i(i({},this.options.buttonText),t.buttonText),r=i(i({},this.options.tooltipText),t.tooltipText);this.options=i(i({},this.options),t),this.options.dropdowns=i({},e),this.options.buttonText=i({},n),this.options.tooltipText=i({},r),!this.options.singleMode||this.options.startDate instanceof o.DateTime||(this.options.startDate=null,this.options.endDate=null),this.options.singleMode||this.options.startDate instanceof o.DateTime&&this.options.endDate instanceof o.DateTime||(this.options.startDate=null,this.options.endDate=null);for(var s=0;s
'),null!==t.url){if(n+='"}this.createFromClickEvent(t,n)}createFromClickEvent(t,e){const n=this.getContextMenuElement();n.classList.contains("action-dropdown")||n.classList.add("action-dropdown"),n.innerHTML=e,n.style.position="fixed",n.style.top=t.clientY+"px",n.style.left=t.clientX+"px";const i=t=>{t.target.classList.contains("dropdown-toggle")||t.target.classList.contains("dropdown-divider")||(n.classList.remove("d-block"),n.classList.contains("d-none")||n.classList.add("d-none"),n.removeEventListener("click",i),document.removeEventListener("click",i))};n.addEventListener("click",i),document.addEventListener("click",i),n.classList.remove("d-none"),n.classList.contains("d-block")||n.classList.add("d-block")}static createForDataTable(t){[].slice.call(document.querySelectorAll(t)).map((t=>{null!==t.querySelector("td.actions div.dropdown-menu")&&t.addEventListener("contextmenu",(e=>{let n=e.target;for(;null!==n;){const t=n.tagName.toUpperCase();if("TH"===t||"TABLE"===t||"BODY"===t)return;if("TR"===t)break;n=n.parentNode}if(null===n||!n.matches("table.dataTable tbody tr"))return;const o=n.querySelector("td.actions div.dropdown-menu");if(null===o)return;e.preventDefault();new i(t.dataset.contextMenu).createFromClickEvent(e,o.innerHTML)}))}))}}},4028:function(t,e,n){n(4975),n(6579),n.g.KimaiPaginatedBoxWidget=n(4100).A,n.g.KimaiReloadPageWidget=n(5170).A,n.g.KimaiColor=n(9997).A,n.g.KimaiStorage=n(5247).A},4100:function(t,e,n){"use strict";n.d(e,{A:function(){return o}});var i=n(2758);class o{constructor(t){this.selector=t;const e=document.querySelector(this.selector);if(void 0!==e.dataset.reload){this.events=e.dataset.reload.split(" ");const t=()=>{let t=null;t=void 0!==document.querySelector(this.selector).dataset.reloadHref?document.querySelector(this.selector).dataset.reloadHref:document.querySelector(this.selector+" ul.pagination li.active a").href,this.loadPage(t)};for(const e of this.events)document.addEventListener(e,t)}document.body.addEventListener("click",(t=>{let e=t.target;e.matches(this.selector+" a.pagination-link")||(e=e.parentNode),e.matches(this.selector+" a.pagination-link")&&(t.preventDefault(),this.loadPage(e.href))}))}static create(t){return new o(t)}loadPage(t){const e=this.selector;document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this.selector}));const n=()=>{document.dispatchEvent(new Event("kimai.reloadedContent"))};window.kimai.getPlugin("fetch").fetch(t).then((t=>{t.text().then((t=>{const o=document.createElement("div");o.innerHTML=t,document.querySelector(e).replaceWith(this._makeScriptExecutable(o.firstElementChild)),i.A.createForDataTable(e+" table.dataTable"),n()}))})).catch((()=>{window.kimai.getPlugin("alert").error("Failed loading selected page"),n()}))}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}}},4975:function(t,e,n){"use strict";n.r(e)},5170:function(t,e,n){"use strict";n.d(e,{A:function(){return i}});class i{constructor(t,e){const n=()=>{e?document.location.reload():this._loadPage(document.location)};for(const e of t.split(" "))document.addEventListener(e,n)}static create(t,e){return null==e&&(e=!1),new i(t,e)}_showOverlay(){document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:"div.page-wrapper"}))}_hideOverlay(){document.dispatchEvent(new Event("kimai.reloadedContent"))}_loadPage(t){this._showOverlay(),window.kimai.getPlugin("fetch").fetch(t).then((t=>{t.text().then((t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector("section.content");document.querySelector("section.content").replaceWith(n),document.dispatchEvent(new Event("kimai.reloadPage")),this._hideOverlay()}))})).catch((()=>{this._hideOverlay(),document.location=t}))}}},5247:function(t,e,n){"use strict";n.d(e,{A:function(){return i}});class i{static set(t,e){window.localStorage.setItem(t,JSON.stringify(e))}static get(t){let e=window.localStorage.getItem(t);return null==e?null:JSON.parse(e)}static remove(t){window.localStorage.removeItem(t)}}},6579:function(t,e,n){"use strict";var i=n(8097);class o{constructor(t){this._translations=t}get(t){return this._translations[t]}has(t){return t in this._translations}}class r{constructor(t){this._configurations=t}get(t){return this._configurations[t]}has(t){return t in this._configurations}isRTL(){return"rtl"===this.get("direction")}getLanguage(){return this.get("locale").replace("_","-")}is24Hours(){return!!this.get("twentyFourHours")}getFirstDayOfWeek(t=!0){void 0===t&&(t=!0);let e=this.get("first_dow_iso");return t||(e%=7),e}}class s{init(){}getId(){return null}setContainer(t){if(!(t instanceof a))throw new Error("Plugin was given an invalid KimaiContainer");this._core=t}getContainer(){return this._core}getConfiguration(t){return this.getContainer().getConfiguration().get(t)}getConfigurations(){return this.getContainer().getConfiguration()}getDateUtils(){return this.getPlugin("date")}getPlugin(t){return this.getContainer().getPlugin(t)}getTranslation(){return this.getContainer().getTranslation()}translate(t){return this.getTranslation().get(t)}escape(t){return this.getPlugin("escape").escapeForHtml(t)}trigger(t,e=null){this.getPlugin("event").trigger(t,e)}fetch(t,e={}){return this.getPlugin("fetch").fetch(t,e)}fetchForm(t,e={},n=null){n=n||t.getAttribute("action");const i=t.getAttribute("method").toUpperCase();if("GET"===i){const i=this.getPlugin("form").convertFormDataToQueryString(t,{},!0);n=n+(n.includes("?")?"&":"?")+i,e={method:"GET",...e}}else"POST"===i&&(e={method:"POST",body:new FormData(t),...e});return this.fetch(n,e)}isMobile(){return Math.max(document.documentElement.clientWidth,window.innerWidth||0)<576}}class a{constructor(t,e){if(!(t instanceof r))throw new Error("Configuration needs to a KimaiConfiguration instance");if(this._configuration=t,!(e instanceof o))throw new Error("Configuration needs to a KimaiTranslation instance");this._translation=e,this._plugins=[]}registerPlugin(t){if(!(t instanceof s))throw new Error("Invalid plugin given, needs to be a KimaiPlugin instance");return t.setContainer(this),this._plugins.push(t),t}getPlugin(t){for(let e of this._plugins)if(null!==e.getId()&&e.getId()===t)return e;throw new Error("Unknown plugin: "+t)}getPlugins(){return this._plugins}getTranslation(){return this._translation}getConfiguration(){return this._configuration}getUser(){return this.getPlugin("user")}}class l extends s{constructor(t){super(),this.dataAttribute=t}getId(){return"datatable-column-visibility"}init(){let t=document.querySelector("["+this.dataAttribute+"]");if(null!==t){this._id=t.getAttribute(this.dataAttribute),this._modal=document.getElementById("modal_"+this._id),this._modal.addEventListener("show.bs.modal",(()=>{this._evaluateCheckboxes()})),this._modal.querySelector("button[data-type=save]").addEventListener("click",(()=>{this._saveVisibility()})),this._modal.querySelector("button[data-type=reset]").addEventListener("click",(t=>{this._resetVisibility(t.currentTarget)})),this._modal.querySelectorAll("input[name=datatable_profile]").forEach((t=>{t.addEventListener("change",(()=>{const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("data-href")).then((()=>{localStorage.setItem("kimai_profile",t.getAttribute("value")),document.location.reload()})).catch((()=>{e.setAttribute("action",t.getAttribute("data-href")),e.submit()}))}))}));for(let t of this._modal.querySelectorAll("form input[type=checkbox]"))t.addEventListener("change",(()=>{this._changeVisibility(t.getAttribute("name"),t.checked)}))}}_evaluateCheckboxes(){const t=this._modal.getElementsByTagName("form")[0],e=document.getElementsByClassName("datatable_"+this._id)[0];for(let n of e.getElementsByTagName("th")){const e=n.getAttribute("data-field");if(null===e)continue;const i=t.querySelector("input[name="+e+"]");null!==i&&(i.checked="none"!==window.getComputedStyle(n).display)}}_saveVisibility(){const t=this._modal.getElementsByTagName("form")[0];this.fetchForm(t).then((()=>{document.location.reload()})).catch((()=>{t.submit()}))}_resetVisibility(t){const e=this._modal.getElementsByTagName("form")[0];this.fetchForm(e,{},t.getAttribute("formaction")).then((()=>{document.location.reload()})).catch((()=>{e.setAttribute("action",t.getAttribute("formaction")),e.submit()}))}_changeVisibility(t,e){for(const n of document.getElementsByClassName("datatable_"+this._id)){let i=null;for(let o of n.getElementsByClassName("col_"+t)){if(null===i){let t="-none",n="d-table-cell";e||(t="-table-cell",n="d-none"),i="",o.classList.forEach((function(e,n,o){-1===e.indexOf(t)&&(i+=" "+e)})),-1===i.indexOf(n)&&(i+=" "+n)}o.className=i}}}}var c=n(9336);class u extends s{init(){[].slice.call(document.querySelectorAll('[data-toggle="tooltip"]')).map((function(t){return new c.m_(t)}));[...document.querySelectorAll(".offcanvas")].map((t=>new c.go(t)));this.getContainer().getPlugin("form").activateForm("div.page-wrapper form"),this._registerModalAutofocus("#remote_form_modal"),this.overlay=null,document.addEventListener("kimai.reloadContent",(t=>{if(null!==this.overlay)return;let e="body";void 0!==t.detail&&null!==t.detail&&(e=t.detail);const n=document.createElement("div");n.innerHTML='
',this.overlay=n.firstElementChild,document.querySelector(e).append(this.overlay)})),document.addEventListener("kimai.reloadedContent",(()=>{null!==this.overlay&&(this.overlay.remove(),this.overlay=null)}))}_registerModalAutofocus(t){if(this.isMobile())return;const e=document.querySelector(t);null!==e&&e.addEventListener("shown.bs.modal",(()=>{const t=e.querySelector("form");let n=t.querySelectorAll("[autofocus]");n.length<1&&(n=t.querySelectorAll("input[type=text],input[type=date],textarea,select")),n.length>0&&n[0].focus()}))}}var d=n(424);n(8214);class h extends s{supportsForm(t){return!1}activateForm(t){}destroyForm(t){}}class p extends h{constructor(t){super(),this._selector=t}init(){window.disableLitepickerStyles=!0,this._pickers=[]}supportsForm(t){return!0}activateForm(t){const e=this.getConfigurations().getFirstDayOfWeek(!1),n=this.getConfigurations().getLanguage();let i={buttonText:{previousMonth:'',nextMonth:'',apply:this.translate("confirm"),cancel:this.translate("cancel")}};const o=[].slice.call(t.querySelectorAll(this._selector)).map((t=>(void 0===t.dataset.format&&console.log("Trying to bind litepicker to an element without data-format attribute"),void 0!==t.hasAttribute("min")&&(i={...i,minDate:t.getAttribute("min")}),void 0!==t.hasAttribute("max")&&(i={...i,maxDate:t.getAttribute("max")}),i={...i,format:t.dataset.format,showTooltip:!1,element:t,lang:n,autoRefresh:!0,firstDay:e,setup:e=>{e.on("preselect",((t,n)=>{e._wasPreselected=!0})),e.on("selected",((n,i)=>{void 0!==e._wasPreselected&&(t.dispatchEvent(new Event("change",{bubbles:!0})),delete e._wasPreselected)})),void 0!==e.backdrop&&document.body.appendChild(e.backdrop)}},[t,new d.Litepicker(this.prepareOptions(i))])));this._pickers=this._pickers.concat(o)}prepareOptions(t){return{...t,plugins:["mobilefriendly"]}}destroyForm(t){[].slice.call(t.querySelectorAll(this._selector)).map((t=>{for(let e=0;e{this.reloadDatatable()};for(let t of e.split(" "))document.addEventListener(t,n);document.addEventListener("pagination-change",n),document.addEventListener("filter-change",n)}registerContextMenu(t){f.A.createForDataTable(t)}reloadDatatable(){const t=this.getContainer().getPlugin("toolbar").getSelector(),e=document.querySelector(t),n=t=>{const e=document.createElement("div");e.innerHTML=t;const n=e.querySelector(this._contentArea);document.querySelector(this._contentArea).replaceWith(n),this.registerContextMenu(this._selector),document.dispatchEvent(new Event("kimai.reloadedContent"))};document.dispatchEvent(new CustomEvent("kimai.reloadContent",{detail:this._contentArea})),null!==e?this.fetchForm(e).then((t=>{t.text().then(n)})).catch((()=>{e.submit()})):this.fetch(document.location).then((t=>{t.text().then(n)})).catch((()=>{document.location.reload()}))}}class v extends s{constructor(t,e){super(),this._formSelector=t,this._actionClass=e}getId(){return"toolbar"}init(){const t=this.getSelector();this._registerPagination(t),this._registerSortableTables(t),this._registerAlternativeSubmitActions(t,this._actionClass),[].slice.call(document.querySelectorAll(t+" input")).map((e=>{e.addEventListener("change",(e=>{switch(e.target.id){case"order":case"orderBy":case"page":break;default:document.querySelector(t+" input#page").value=1}})),this.triggerChange()})),[].slice.call(document.querySelectorAll(t+" select")).map((e=>{e.addEventListener("change",(e=>{let n=!0;switch(e.target.id){case"customer":null!==document.querySelector(t+" select#project")&&(n=!1);break;case"project":null!==document.querySelector(t+" select#activity")&&(n=!1)}document.querySelector(t+" input#page").value=1,n&&this.triggerChange()}))}))}_registerAlternativeSubmitActions(t,e){document.addEventListener("click",(function(n){let i=n.target;for(;null!==i&&"function"==typeof i.matches&&!i.matches("body");){if(i.classList.contains(e)){const e=document.querySelector(t);if(null===e)return;const o=e.getAttribute("action"),r=e.getAttribute("method");void 0!==i.dataset.target&&(e.target=i.dataset.target),e.action=i.href,void 0!==i.dataset.method&&(e.method=i.dataset.method),e.submit(),e.target="",e.action=o,e.method=r,n.preventDefault(),n.stopPropagation()}i=i.parentNode}}))}_registerSortableTables(t){document.body.addEventListener("click",(e=>{if(!e.target.matches("th.sortable"))return;let n="DESC",i=e.target.dataset.order;e.target.classList.contains("sorting_desc")&&(n="ASC"),document.querySelector(t+" #orderBy").value=i,document.querySelector(t+" #order").value=n,document.querySelector(t+" #orderBy").dispatchEvent(new Event("change")),document.querySelector(t+" #order").dispatchEvent(new Event("change")),document.dispatchEvent(new Event("filter-change"))}))}_registerPagination(t){document.body.addEventListener("click",(e=>{if(!(e.target.matches("ul.pagination li a")||null!==e.target.parentNode&&e.target.parentNode.matches("ul.pagination li a")))return;let n=document.querySelector(t+" input#page");if(null===n)return;let i=e.target;i.matches("a")||(i=i.parentNode),e.preventDefault(),e.stopPropagation();let o=i.href.split("/"),r=o[o.length-1];return/\d/.test(r)||(r=1),n.value=r,n.dispatchEvent(new Event("change")),document.dispatchEvent(new Event("pagination-change")),!1}))}triggerChange(){document.dispatchEvent(new Event("toolbar-change"))}getSelector(){return this._formSelector}}class y extends s{getId(){return"api"}_headers(){const t=new Headers;return t.append("Content-Type","application/json"),t}get(t,e,n,i){if(void 0!==e){const n=new URLSearchParams(e).toString();""!==n&&(t=t+(t.includes("?")?"&":"?")+n)}void 0===i&&(i=t=>{this.handleError("An error occurred",t)}),this.fetch(t,{method:"GET",headers:this._headers()}).then((t=>{t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}post(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"POST",body:this._parseData(e),headers:this._headers()}).then((t=>{t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}patch(t,e,n,i){void 0===i&&(i=t=>{this.handleError("action.update.error",t)}),this.fetch(t,{method:"PATCH",body:this._parseData(e),headers:this._headers()}).then((t=>{204===t.statusCode?n():t.json().then((t=>{n(t)}))})).catch((t=>{i(t)}))}delete(t,e,n){void 0===n&&(n=t=>{this.handleError("action.delete.error",t)}),this.fetch(t,{method:"DELETE",headers:this._headers()}).then((()=>{e()})).catch((t=>{n(t)}))}_parseData(t){return"object"==typeof t?JSON.stringify(t):t}handleError(t,e){if(void 0===e.headers)return;const n=e.headers.get("content-type");n&&-1!==n.indexOf("application/json")?e.json().then((n=>{let i=n.message;if(400===e.status&&n.errors){let t=[""+i+""];if(n.errors.errors)for(let e of n.errors.errors)t.push(e);if(n.errors.children)for(let e in n.errors.children){let i=n.errors.children[e];if(void 0!==i.errors&&i.errors.length>0)for(let e of i.errors)t.push(e)}t.length>0&&(i=t)}this.getPlugin("alert").error(t,i)})):e.text().then((()=>{const n="["+e.statusCode+"] "+e.statusText;this.getPlugin("alert").error(t,n)}))}}class b extends s{addClickHandler(t,e,n){document.body.addEventListener("click",(i=>{let o=i.target;for(;null!==o;){const e=o.tagName.toUpperCase();if("BODY"===e)return;if(o.matches(t))break;if("A"===e||"BUTTON"===e||"INPUT"===e||"LABEL"===e)return;for(let t of n)if(o.matches(t))return;o=o.parentNode}if(null===o)return;if(o.isContentEditable||o.parentNode.isContentEditable)return;if(!o.matches(t))return;for(let t of n)if(o.matches(t))return;i.preventDefault(),i.stopPropagation();let r=o.dataset.href;null==r&&(r=o.href),null!=r&&""!==r&&e(r)}))}}class _ extends b{constructor(t){super(),this._selector=t}init(){this.addClickHandler(this._selector,(function(t){window.location=t}),[])}}class w extends b{constructor(t,e){super(),this._selector=t,this._stopSelector=e}getId(){return"modal"}init(){this._isDirty=!1;const t=this._getModalElement();null!==t&&(t.addEventListener("hide.bs.modal",(e=>{if(this._isDirty){if(null===t.querySelector(".modal-body .remote_modal_is_dirty_warning")){const e=this.translate("modal.dirty"),n=document.createElement("div");n.innerHTML='

'+e+"

",t.querySelector(".modal-body").prepend(n.firstElementChild)}e.preventDefault()}else this._isDirty=!1,document.dispatchEvent(new Event("modal-hide"))})),t.addEventListener("hidden.bs.modal",(()=>{this.getContainer().getPlugin("form").destroyForm(this._getFormIdentifier()),t.querySelector(".modal-body").replaceWith("")})),t.addEventListener("show.bs.modal",(()=>{document.dispatchEvent(new Event("modal-show"))})),this.addClickHandler(this._selector,(t=>{this.openUrlInModal(t)}),this._stopSelector))}_getModal(){return c.aF.getOrCreateInstance(this._getModalElement())}openUrlInModal(t,e){const n=new Headers;n.append("X-Requested-With","Kimai-Modal"),this.fetch(t,{method:"GET",redirect:"follow",headers:n}).then((e=>{if(e.ok)return e.text().then((t=>{this._openFormInModal(t)}));window.location=t})).catch((n=>{null==e?window.location=t:e(n)}))}_getFormIdentifier(){return"#remote_form_modal .modal-content form"}_getModalElement(){return document.getElementById("remote_form_modal")}_makeScriptExecutable(t){if(void 0!==t.tagName&&"SCRIPT"===t.tagName){const e=document.createElement("script");e.text=t.innerHTML,t.parentNode.replaceChild(e,t)}else for(const e of t.childNodes)this._makeScriptExecutable(e);return t}_openFormInModal(t){const e=this._getFormIdentifier();let n=this._getModalElement();const i=document.createElement("div");i.innerHTML=t;const o=this._makeScriptExecutable(i.querySelector("#form_modal .modal-content"));if(null!==o){let t=n.querySelector(".modal-dialog"),r=i.querySelector(".modal-dialog").classList.contains("modal-lg");r&&!t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),!r&&t.classList.contains("modal-lg")&&t.classList.toggle("modal-lg"),n.querySelector(".modal-content").replaceWith(o),[].slice.call(n.querySelectorAll('[data-bs-dismiss="modal"]')).map((t=>{t.addEventListener("click",(()=>{this._isDirty=!1,this._getModal().hide()}))})),this.getContainer().getPlugin("form").activateForm(e)}let r=i.querySelector("div.alert");null!==r&&n.querySelector(".modal-body").prepend(r);const s=document.querySelector(e);s.addEventListener("change",(()=>{this._isDirty=!0})),s.addEventListener("submit",this._getEventHandler()),this._getModal().show()}_getEventHandler(){return void 0===this.eventHandler&&(this.eventHandler=t=>{const e=t.target;if(void 0!==e.target&&""!==e.target)return!0;const n=document.querySelector(this._getFormIdentifier()+" button[type=submit]");n.textContent=n.textContent+" …",n.disabled=!0;const i=e.dataset.formEvent,o=this.getContainer().getPlugin("event"),r=this.getContainer().getPlugin("alert");t.preventDefault(),t.stopPropagation();const s=new Headers;s.append("X-Requested-With","Kimai-Modal");const a={headers:s};this.fetchForm(e,a).then((t=>{t.text().then((t=>{const s=document.createElement("div");s.innerHTML=t;let a=!1,l=!1,c=!1;n.textContent=n.textContent.replace(" …",""),n.disabled=!1;const u=s.querySelector("#form_modal .modal-content");if(null!==u&&(a=null!==u.querySelector(".is-invalid"),a||(a=null!==u.querySelector(".invalid-feedback")),l=null!==u.querySelector("ul.list-unstyled li.text-danger"),c=null!==s.querySelector("div.alert-danger")),a||l||c)this._openFormInModal(t);else{o.trigger(i);let t=e.dataset.msgSuccess;null!=t&&""!==t||(t="action.update.success"),this._isDirty=!1,this._getModal().hide(),r.success(t)}}))})).catch((t=>{let i=e.dataset.msgError;null!=i&&""!==i||(i="action.update.error"),r.error(i,t.message),setTimeout((()=>{n.textContent=n.textContent.replace(" …",""),n.disabled=!1}),1500)}))}),this.eventHandler}}class k extends s{constructor(){super(),this._selector=".ticktac-menu",this._selectorEmpty=".ticktac-menu-empty",this._favIconUrl=null}getId(){return"active-records"}init(){if(null===document.querySelector(this._selector))return;const t=()=>{this.reloadActiveRecords()};document.addEventListener("kimai.timesheetUpdate",t),document.addEventListener("kimai.timesheetDelete",t),document.addEventListener("kimai.activityUpdate",t),document.addEventListener("kimai.activityDelete",t),document.addEventListener("kimai.projectUpdate",t),document.addEventListener("kimai.projectDelete",t),document.addEventListener("kimai.customerUpdate",t),document.addEventListener("kimai.customerDelete",t),this._updateBrowserTitle=!!this.getConfiguration("updateBrowserTitle");const e=()=>{this._updateDuration()};this._updatesHandler=setInterval(e,1e4),document.addEventListener("kimai.timesheetUpdate",e),document.addEventListener("kimai.reloadedContent",e)}_updateDuration(){const t=document.querySelectorAll('[data-since]:not([data-since=""])');if(this._updateBrowserTitle&&this._changeFavicon(t.length>0),0===t.length)return void(this._updateBrowserTitle&&(void 0===document.body.dataset.title?this._updateBrowserTitle=!1:document.title=document.body.dataset.title));const e=this.getDateUtils();let n=[];for(const i of t){const t=e.formatDuration(i.dataset.since);void 0!==i.dataset.replacer&&null!==i.dataset.title&&"?"!==t&&n.push(t),i.textContent=t}0!==n.length&&this._updateBrowserTitle&&(document.title=n.shift())}_setEntries(t){const e=t.length>0;for(let t of document.querySelectorAll(this._selectorEmpty))t.style.display=e?"none":"inline-block";for(let n of document.querySelectorAll(this._selector)){if(n.style.display=e?"inline-block":"none",!e)for(let t of n.querySelectorAll("[data-since]"))t.dataset.since="";const i=n.querySelector(".ticktac-stop");e?(i&&(i.accesskey="s"),this._replaceInNode(n,t[0])):i&&(i.accesskey=null)}this._updateDuration()}_replaceInNode(t,e){const n=this.getDateUtils(),i=t.querySelectorAll("[data-replacer]");for(let o of i){const i=o.dataset.replacer;"url"===i?o.dataset.href=t.dataset.href.replace("000",e.id):"activity"===i?o.innerText=e.activity.name:"project"===i?o.innerText=e.project.name:"customer"===i?o.innerText=e.project.customer.name:"duration"===i&&(o.dataset.since=e.begin,o.innerText=n.formatDuration(e.duration))}}reloadActiveRecords(){const t=this.getContainer().getPlugin("api"),e=document.querySelector(this._selector).dataset.api;t.get(e,{},(t=>{this._setEntries(t)}))}_changeFavicon(t){const e=document.createElement("canvas"),n=document.getElementById("favicon");null===this._favIconUrl&&(this._favIconUrl=n.href);const i=n.cloneNode(!0);if(e.getContext&&i){const o=window.devicePixelRatio,r=document.createElement("img");e.height=e.width=16*o,r.onload=function(){const r=e.getContext("2d");if(r.drawImage(this,0,0,e.width,e.height),t){const t=5.5*o;r.fillStyle="rgb(182,57,57)",r.fillRect(e.width/2-t/2,e.height/2-t/2,t,t)}i.href=e.toDataURL("image/png"),n.remove(),document.head.appendChild(i)},r.src=this._favIconUrl}}}class E extends s{getId(){return"event"}trigger(t,e=null){if(""!==t)for(const n of t.split(" ")){let t=new Event(n);null!==e&&(t=new CustomEvent(n,{detail:e})),document.dispatchEvent(t)}}}class D extends s{constructor(t){super(),this._selector=t}init(){document.addEventListener("click",(t=>{let e=t.target;for(;null!==e&&"function"==typeof e.matches&&!e.matches("body");){if(e.classList.contains(this._selector)){const n=e.dataset;let i=n.href;i||(i=e.getAttribute("href")),void 0!==n.question?this.getContainer().getPlugin("alert").question(n.question,(t=>{t&&this._callApi(i,n)})):this._callApi(i,n),t.preventDefault(),t.stopPropagation()}e=e.parentNode}}))}_callApi(t,e){const n=e.method,i=e.event,o=this.getContainer().getPlugin("api"),r=this.getContainer().getPlugin("event"),s=this.getContainer().getPlugin("alert"),a=()=>{r.trigger(i),void 0!==e.msgSuccess&&s.success(e.msgSuccess)},l=t=>{let n="action.update.error";void 0!==e.msgError&&(n=e.msgError),o.handleError(n,t)};let c={};if(void 0!==e.payload&&(c=e.payload),"PATCH"===n)o.patch(t,c,a,l);else if("POST"===n){let e={};o.post(t,e,a,l)}else"DELETE"===n?o.delete(t,a,l):"GET"===n&&o.get(t,c,a,l)}}class T extends s{getId(){return"alert"}error(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t)),t=t.replace("%reason%",""),void 0===e&&(e=null),null!==e&&(n.has(e)&&(e=n.get(e)),Array.isArray(e)&&(e=e.join("
")));const i="alert_global_error",o=document.getElementById(i);null!==o&&c.aF.getOrCreateInstance(o).hide();const r='\n
\n ";this._showModal(r)}warning(t){this._show("warning",t)}success(t){this._toast("success",t)}info(t){this._show("info",t)}_showModal(t){const e=document.body,n=document.createElement("template");n.innerHTML=t.trim();const i=n.content.firstChild;e.appendChild(i);const o=new c.aF(i);i.addEventListener("hidden.bs.modal",(function(){e.removeChild(i)})),o.show()}_show(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));const i='\n \n ";this._showModal(i)}_mapClass(t){return"info"===t||"success"===t||"warning"===t||"danger"===t?t:"error"===t?"danger":"primary"}_toast(t,e){const n=this.getTranslation();n.has(e)&&(e=n.get(e));let i='';"success"===t?i='':"warning"===t?i='':"danger"!==t&&"error"!==t||(i='');const o='',r=document.getElementById("toast-container"),s=document.createElement("template");s.innerHTML=o.trim();const a=s.content.firstChild;r.appendChild(a);const l=new c.y8(a);a.addEventListener("hidden.bs.toast",(function(){r.removeChild(a)})),l.show()}question(t,e){const n=this.getTranslation();n.has(t)&&(t=n.get(t));const i=this._mapClass("info"),o='\n \n ",r=document.body,s=document.createElement("template");s.innerHTML=o.trim();const a=s.content.firstChild;r.appendChild(a),a.querySelector(".question-confirm").addEventListener("click",(()=>{e(!0)})),a.querySelector(".question-cancel").addEventListener("click",(()=>{e(!1)}));const l=new c.aF(a);a.addEventListener("hidden.bs.modal",(()=>{r.removeChild(a)})),l.show()}}function S(t,e){t.split(/\s+/).forEach((t=>{e(t)}))}class x{constructor(){this._events={}}on(t,e){S(t,(t=>{const n=this._events[t]||[];n.push(e),this._events[t]=n}))}off(t,e){var n=arguments.length;0!==n?S(t,(t=>{if(1===n)return void delete this._events[t];const i=this._events[t];void 0!==i&&(i.splice(i.indexOf(e),1),this._events[t]=i)})):this._events={}}trigger(t,...e){var n=this;S(t,(t=>{const i=n._events[t];void 0!==i&&i.forEach((t=>{t.apply(n,e)}))}))}}const O=t=>(t=t.filter(Boolean)).length<2?t[0]||"":1==I(t)?"["+t.join("")+"]":"(?:"+t.join("|")+")",C=t=>{if(!M(t))return t.join("");let e="",n=0;const i=()=>{n>1&&(e+="{"+n+"}")};return t.forEach(((o,r)=>{o!==t[r-1]?(i(),e+=o,n=1):n++})),i(),e},L=t=>{let e=Array.from(t);return O(e)},M=t=>new Set(t).size!==t.length,A=t=>(t+"").replace(/([\$\(\)\*\+\.\?\[\]\^\{\|\}\\])/gu,"\\$1"),I=t=>t.reduce(((t,e)=>Math.max(t,N(e))),0),N=t=>Array.from(t).length,P=t=>{if(1===t.length)return[[t]];let e=[];const n=t.substring(1);return P(n).forEach((function(n){let i=n.slice(0);i[0]=t.charAt(0)+i[0],e.push(i),i=n.slice(0),i.unshift(t.charAt(0)),e.push(i)})),e},F=[[0,65535]];let j,q;const H={},V={"/":"⁄∕",0:"߀",a:"ⱥɐɑ",aa:"ꜳ",ae:"æǽǣ",ao:"ꜵ",au:"ꜷ",av:"ꜹꜻ",ay:"ꜽ",b:"ƀɓƃ",c:"ꜿƈȼↄ",d:"đɗɖᴅƌꮷԁɦ",e:"ɛǝᴇɇ",f:"ꝼƒ",g:"ǥɠꞡᵹꝿɢ",h:"ħⱨⱶɥ",i:"ɨı",j:"ɉȷ",k:"ƙⱪꝁꝃꝅꞣ",l:"łƚɫⱡꝉꝇꞁɭ",m:"ɱɯϻ",n:"ꞥƞɲꞑᴎлԉ",o:"øǿɔɵꝋꝍᴑ",oe:"œ",oi:"ƣ",oo:"ꝏ",ou:"ȣ",p:"ƥᵽꝑꝓꝕρ",q:"ꝗꝙɋ",r:"ɍɽꝛꞧꞃ",s:"ßȿꞩꞅʂ",t:"ŧƭʈⱦꞇ",th:"þ",tz:"ꜩ",u:"ʉ",v:"ʋꝟʌ",vy:"ꝡ",w:"ⱳ",y:"ƴɏỿ",z:"ƶȥɀⱬꝣ",hv:"ƕ"};for(let t in V){let e=V[t]||"";for(let n=0;nt.normalize(e),$=t=>Array.from(t).reduce(((t,e)=>t+W(e)),""),W=t=>(t=B(t).toLowerCase().replace(R,(t=>H[t]||"")),B(t,"NFC"));const Y=t=>{const e={},n=(t,n)=>{const i=e[t]||new Set,o=new RegExp("^"+L(i)+"$","iu");n.match(o)||(i.add(A(n)),e[t]=i)};for(let e of function*(t){for(const[e,n]of t)for(let t=e;t<=n;t++){let e=String.fromCharCode(t),n=$(e);n!=e.toLowerCase()&&(n.length>3||0!=n.length&&(yield{folded:n,composed:e,code_point:t}))}}(t))n(e.folded,e.folded),n(e.folded,e.composed);return e},z=t=>{const e=Y(t),n={};let i=[];for(let t in e){let o=e[t];o&&(n[t]=L(o)),t.length>1&&i.push(A(t))}i.sort(((t,e)=>e.length-t.length));const o=O(i);return q=new RegExp("^"+o,"u"),n},U=(t,e=1)=>(e=Math.max(e,t.length-1),O(P(t).map((t=>((t,e=1)=>{let n=0;return t=t.map((t=>(j[t]&&(n+=t.length),j[t]||t))),n>=e?C(t):""})(t,e))))),Z=(t,e=!0)=>{let n=t.length>1?1:0;return O(t.map((t=>{let i=[];const o=e?t.length():t.length()-1;for(let e=0;e{for(const n of e){if(n.start!=t.start||n.end!=t.end)continue;if(n.substrs.join("")!==t.substrs.join(""))continue;let e=t.parts;const i=t=>{for(const n of e){if(n.start===t.start&&n.substr===t.substr)return!1;if(1!=t.length&&1!=n.length){if(t.startn.start)return!0;if(n.startt.start)return!0}}return!1};if(!(n.parts.filter(i).length>0))return!0}return!1};class K{parts;substrs;start;end;constructor(){this.parts=[],this.substrs=[],this.start=0,this.end=0}add(t){t&&(this.parts.push(t),this.substrs.push(t.substr),this.start=Math.min(t.start,this.start),this.end=Math.max(t.end,this.end))}last(){return this.parts[this.parts.length-1]}length(){return this.parts.length}clone(t,e){let n=new K,i=JSON.parse(JSON.stringify(this.parts)),o=i.pop();for(const t of i)n.add(t);let r=e.substr.substring(0,t-o.start),s=r.length;return n.add({start:o.start,end:o.start+s,length:s,substr:r}),n}}const J=t=>{var e;void 0===j&&(j=z(e||F)),t=$(t);let n="",i=[new K];for(let e=0;e0){a=a.sort(((t,e)=>t.length()-e.length()));for(let t of a)X(t,i)||i.push(t)}else if(e>0&&1==l.size&&!l.has("3")){n+=Z(i,!1);let t=new K;const e=i[0];e&&t.add(e.last()),i=[t]}}return n+=Z(i,!0),n},G=(t,e)=>{if(t)return t[e]},Q=(t,e)=>{if(t){for(var n,i=e.split(".");(n=i.shift())&&(t=t[n]););return t}},tt=(t,e,n)=>{var i,o;return t?(t+="",null==e.regex||-1===(o=t.search(e.regex))?0:(i=e.string.length/t.length,0===o&&(i+=.5),i*n)):0},et=(t,e)=>{var n=t[e];if("function"==typeof n)return n;n&&!Array.isArray(n)&&(t[e]=[n])},nt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},it=(t,e)=>"number"==typeof t&&"number"==typeof e?t>e?1:t(e=$(e+"").toLowerCase())?1:e>t?-1:0;class ot{items;settings;constructor(t,e){this.items=t,this.settings=e||{diacritics:!0}}tokenize(t,e,n){if(!t||!t.length)return[];const i=[],o=t.split(/\s+/);var r;return n&&(r=new RegExp("^("+Object.keys(n).map(A).join("|")+"):(.*)$")),o.forEach((t=>{let n,o=null,s=null;r&&(n=t.match(r))&&(o=n[1],t=n[2]),t.length>0&&(s=this.settings.diacritics?J(t)||null:A(t),s&&e&&(s="\\b"+s)),i.push({string:t,regex:s?new RegExp(s,"iu"):null,field:o})})),i}getScoreFunction(t,e){var n=this.prepareSearch(t,e);return this._getScoreFunction(n)}_getScoreFunction(t){const e=t.tokens,n=e.length;if(!n)return function(){return 0};const i=t.options.fields,o=t.weights,r=i.length,s=t.getAttrFn;if(!r)return function(){return 1};const a=1===r?function(t,e){const n=i[0].field;return tt(s(e,n),t,o[n]||1)}:function(t,e){var n=0;if(t.field){const i=s(e,t.field);!t.regex&&i?n+=1/r:n+=tt(i,t,1)}else nt(o,((i,o)=>{n+=tt(s(e,o),t,i)}));return n/r};return 1===n?function(t){return a(e[0],t)}:"and"===t.options.conjunction?function(t){var i,o=0;for(let n of e){if((i=a(n,t))<=0)return 0;o+=i}return o/n}:function(t){var i=0;return nt(e,(e=>{i+=a(e,t)})),i/n}}getSortFunction(t,e){var n=this.prepareSearch(t,e);return this._getSortFunction(n)}_getSortFunction(t){var e,n=[];const i=this,o=t.options,r=!t.query&&o.sort_empty?o.sort_empty:o.sort;if("function"==typeof r)return r.bind(this);const s=function(e,n){return"$score"===e?n.score:t.getAttrFn(i.items[n.id],e)};if(r)for(let e of r)(t.query||"$score"!==e.field)&&n.push(e);if(t.query){e=!0;for(let t of n)if("$score"===t.field){e=!1;break}e&&n.unshift({field:"$score",direction:"desc"})}else n=n.filter((t=>"$score"!==t.field));return n.length?function(t,e){var i,o;for(let r of n){if(o=r.field,i=("desc"===r.direction?-1:1)*it(s(o,t),s(o,e)))return i}return 0}:null}prepareSearch(t,e){const n={};var i=Object.assign({},e);if(et(i,"sort"),et(i,"sort_empty"),i.fields){et(i,"fields");const t=[];i.fields.forEach((e=>{"string"==typeof e&&(e={field:e,weight:1}),t.push(e),n[e.field]="weight"in e?e.weight:1})),i.fields=t}return{options:i,query:t.toLowerCase().trim(),tokens:this.tokenize(t,i.respect_word_boundaries,n),total:0,items:[],weights:n,getAttrFn:i.nesting?Q:G}}search(t,e){var n,i,o=this;i=this.prepareSearch(t,e),e=i.options,t=i.query;const r=e.score||o._getScoreFunction(i);t.length?nt(o.items,((t,o)=>{n=r(t),(!1===e.filter||n>0)&&i.items.push({score:n,id:o})})):nt(o.items,((t,e)=>{i.items.push({score:1,id:e})}));const s=o._getSortFunction(i);return s&&i.items.sort(s),i.total=i.items.length,"number"==typeof e.limit&&(i.items=i.items.slice(0,e.limit)),i}}const rt=t=>null==t?null:st(t),st=t=>"boolean"==typeof t?t?"1":"0":t+"",at=t=>(t+"").replace(/&/g,"&").replace(//g,">").replace(/"/g,"""),lt=(t,e)=>{var n;return function(i,o){var r=this;n&&(r.loading=Math.max(r.loading-1,0),clearTimeout(n)),n=setTimeout((function(){n=null,r.loadedSearches[i]=!0,t.call(r,i,o)}),e)}},ct=(t,e,n)=>{var i,o=t.trigger,r={};for(i of(t.trigger=function(){var n=arguments[0];if(-1===e.indexOf(n))return o.apply(t,arguments);r[n]=arguments},n.apply(t,[]),t.trigger=o,e))i in r&&o.apply(t,r[i])},ut=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},dt=(t,e,n,i)=>{t.addEventListener(e,n,i)},ht=(t,e)=>!!e&&(!!e[t]&&1===(e.altKey?1:0)+(e.ctrlKey?1:0)+(e.shiftKey?1:0)+(e.metaKey?1:0)),pt=(t,e)=>{const n=t.getAttribute("id");return n||(t.setAttribute("id",e),e)},mt=t=>t.replace(/[\\"']/g,"\\$&"),ft=(t,e)=>{e&&t.append(e)},gt=(t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)},vt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(yt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},yt=t=>"string"==typeof t&&t.indexOf("<")>-1,bt=(t,e)=>{var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!1),t.dispatchEvent(n)},_t=(t,e)=>{Object.assign(t.style,e)},wt=(t,...e)=>{var n=Et(e);(t=Dt(t)).map((t=>{n.map((e=>{t.classList.add(e)}))}))},kt=(t,...e)=>{var n=Et(e);(t=Dt(t)).map((t=>{n.map((e=>{t.classList.remove(e)}))}))},Et=t=>{var e=[];return gt(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Dt=t=>(Array.isArray(t)||(t=[t]),t),Tt=(t,e,n)=>{if(!n||n.contains(t))for(;t&&t.matches;){if(t.matches(e))return t;t=t.parentNode}},St=(t,e=0)=>e>0?t[t.length-1]:t[0],xt=(t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n},Ot=(t,e)=>{gt(e,((e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)}))},Ct=(t,e)=>{t.parentNode&&t.parentNode.replaceChild(e,t)},Lt=(t,e)=>{if(null===e)return;if("string"==typeof e){if(!e.length)return;e=new RegExp(e,"i")}const n=t=>3===t.nodeType?(t=>{var n=t.data.match(e);if(n&&t.data.length>0){var i=document.createElement("span");i.className="highlight";var o=t.splitText(n.index);o.splitText(n[0].length);var r=o.cloneNode(!0);return i.appendChild(r),Ct(o,i),1}return 0})(t):((t=>{1!==t.nodeType||!t.childNodes||/(script|style)/i.test(t.tagName)||"highlight"===t.className&&"SPAN"===t.tagName||Array.from(t.childNodes).forEach((t=>{n(t)}))})(t),0);n(t)},Mt="undefined"!=typeof navigator&&/Mac/.test(navigator.userAgent)?"metaKey":"ctrlKey";var At={options:[],optgroups:[],plugins:[],delimiter:",",splitOn:null,persist:!0,diacritics:!0,create:null,createOnBlur:!1,createFilter:null,highlight:!0,openOnFocus:!0,shouldOpen:null,maxOptions:50,maxItems:null,hideSelected:null,duplicates:!1,addPrecedence:!1,selectOnTab:!1,preload:null,allowEmptyOption:!1,refreshThrottle:300,loadThrottle:300,loadingClass:"loading",dataAttr:null,optgroupField:"optgroup",valueField:"value",labelField:"text",disabledField:"disabled",optgroupLabelField:"label",optgroupValueField:"value",lockOptgroupOrder:!1,sortField:"$order",searchField:["text"],searchConjunction:"and",mode:null,wrapperClass:"ts-wrapper",controlClass:"ts-control",dropdownClass:"ts-dropdown",dropdownContentClass:"ts-dropdown-content",itemClass:"item",optionClass:"option",dropdownParent:null,controlInput:'',copyClassesToDropdown:!1,placeholder:null,hidePlaceholder:null,shouldLoad:function(t){return t.length>0},render:{}};function It(t,e){var n=Object.assign({},At,e),i=n.dataAttr,o=n.labelField,r=n.valueField,s=n.disabledField,a=n.optgroupField,l=n.optgroupLabelField,c=n.optgroupValueField,u=t.tagName.toLowerCase(),d=t.getAttribute("placeholder")||t.getAttribute("data-placeholder");if(!d&&!n.allowEmptyOption){let e=t.querySelector('option[value=""]');e&&(d=e.textContent)}var h={placeholder:d,options:[],optgroups:[],items:[],maxItems:null};return"select"===u?(()=>{var e,u=h.options,d={},p=1;let m=0;var f=t=>{var e=Object.assign({},t.dataset),n=i&&e[i];return"string"==typeof n&&n.length&&(e=Object.assign(e,JSON.parse(n))),e},g=(t,e)=>{var i=rt(t.value);if(null!=i&&(i||n.allowEmptyOption)){if(d.hasOwnProperty(i)){if(e){var l=d[i][a];l?Array.isArray(l)?l.push(e):d[i][a]=[l,e]:d[i][a]=e}}else{var c=f(t);c[o]=c[o]||t.textContent,c[r]=c[r]||i,c[s]=c[s]||t.disabled,c[a]=c[a]||e,c.$option=t,c.$order=c.$order||++m,d[i]=c,u.push(c)}t.selected&&h.items.push(i)}};h.maxItems=t.hasAttribute("multiple")?null:1,gt(t.children,(t=>{var n,i,o;"optgroup"===(e=t.tagName.toLowerCase())?((o=f(n=t))[l]=o[l]||n.getAttribute("label")||"",o[c]=o[c]||p++,o[s]=o[s]||n.disabled,o.$order=o.$order||++m,h.optgroups.push(o),i=o[c],gt(n.children,(t=>{g(t,i)}))):"option"===e&&g(t)}))})():(()=>{const e=t.getAttribute(i);if(e)h.options=JSON.parse(e),gt(h.options,(t=>{h.items.push(t[r])}));else{var s=t.value.trim()||"";if(!n.allowEmptyOption&&!s.length)return;const e=s.split(n.delimiter);gt(e,(t=>{const e={};e[o]=t,e[r]=t,h.options.push(e)})),h.items=e}})(),Object.assign({},At,h,e)}var Nt=0;class Pt extends(function(t){return t.plugins={},class extends t{constructor(){super(...arguments),this.plugins={names:[],settings:{},requested:{},loaded:{}}}static define(e,n){t.plugins[e]={name:e,fn:n}}initializePlugins(t){var e,n;const i=this,o=[];if(Array.isArray(t))t.forEach((t=>{"string"==typeof t?o.push(t):(i.plugins.settings[t.name]=t.options,o.push(t.name))}));else if(t)for(e in t)t.hasOwnProperty(e)&&(i.plugins.settings[e]=t[e],o.push(e));for(;n=o.shift();)i.require(n)}loadPlugin(e){var n=this,i=n.plugins,o=t.plugins[e];if(!t.plugins.hasOwnProperty(e))throw new Error('Unable to find "'+e+'" plugin');i.requested[e]=!0,i.loaded[e]=o.fn.apply(n,[n.plugins.settings[e]||{}]),i.names.push(e)}require(t){var e=this,n=e.plugins;if(!e.plugins.loaded.hasOwnProperty(t)){if(n.requested[t])throw new Error('Plugin has circular dependency ("'+t+'")');e.loadPlugin(t)}return n.loaded[t]}}}(x)){constructor(t,e){var n;super(),this.order=0,this.isOpen=!1,this.isDisabled=!1,this.isReadOnly=!1,this.isInvalid=!1,this.isValid=!0,this.isLocked=!1,this.isFocused=!1,this.isInputHidden=!1,this.isSetup=!1,this.ignoreFocus=!1,this.ignoreHover=!1,this.hasOptions=!1,this.lastValue="",this.caretPos=0,this.loading=0,this.loadedSearches={},this.activeOption=null,this.activeItems=[],this.optgroups={},this.options={},this.userOptions={},this.items=[],this.refreshTimeout=null,Nt++;var i=vt(t);if(i.tomselect)throw new Error("Tom Select already initialized on this element");i.tomselect=this,n=(window.getComputedStyle&&window.getComputedStyle(i,null)).getPropertyValue("direction");const o=It(i,e);this.settings=o,this.input=i,this.tabIndex=i.tabIndex||0,this.is_select_tag="select"===i.tagName.toLowerCase(),this.rtl=/rtl/i.test(n),this.inputId=pt(i,"tomselect-"+Nt),this.isRequired=i.required,this.sifter=new ot(this.options,{diacritics:o.diacritics}),o.mode=o.mode||(1===o.maxItems?"single":"multi"),"boolean"!=typeof o.hideSelected&&(o.hideSelected="multi"===o.mode),"boolean"!=typeof o.hidePlaceholder&&(o.hidePlaceholder="multi"!==o.mode);var r=o.createFilter;"function"!=typeof r&&("string"==typeof r&&(r=new RegExp(r)),r instanceof RegExp?o.createFilter=t=>r.test(t):o.createFilter=t=>this.settings.duplicates||!this.options[t]),this.initializePlugins(o.plugins),this.setupCallbacks(),this.setupTemplates();const s=vt("
"),a=vt("
"),l=this._render("dropdown"),c=vt('
'),u=this.input.getAttribute("class")||"",d=o.mode;var h;if(wt(s,o.wrapperClass,u,d),wt(a,o.controlClass),ft(s,a),wt(l,o.dropdownClass,d),o.copyClassesToDropdown&&wt(l,u),wt(c,o.dropdownContentClass),ft(l,c),vt(o.dropdownParent||s).appendChild(l),yt(o.controlInput)){h=vt(o.controlInput);gt(["autocorrect","autocapitalize","autocomplete","spellcheck"],(t=>{i.getAttribute(t)&&Ot(h,{[t]:i.getAttribute(t)})})),h.tabIndex=-1,a.appendChild(h),this.focus_node=h}else o.controlInput?(h=vt(o.controlInput),this.focus_node=h):(h=vt(""),this.focus_node=a);this.wrapper=s,this.dropdown=l,this.dropdown_content=c,this.control=a,this.control_input=h,this.setup()}setup(){const t=this,e=t.settings,n=t.control_input,i=t.dropdown,o=t.dropdown_content,r=t.wrapper,s=t.control,a=t.input,l=t.focus_node,c={passive:!0},u=t.inputId+"-ts-dropdown";Ot(o,{id:u}),Ot(l,{role:"combobox","aria-haspopup":"listbox","aria-expanded":"false","aria-controls":u});const d=pt(l,t.inputId+"-ts-control"),h="label[for='"+(t=>t.replace(/['"\\]/g,"\\$&"))(t.inputId)+"']",p=document.querySelector(h),m=t.focus.bind(t);if(p){dt(p,"click",m),Ot(p,{for:d});const e=pt(p,t.inputId+"-ts-label");Ot(l,{"aria-labelledby":e}),Ot(o,{"aria-labelledby":e})}if(r.style.width=a.style.width,t.plugins.names.length){const e="plugin-"+t.plugins.names.join(" plugin-");wt([r,i],e)}(null===e.maxItems||e.maxItems>1)&&t.is_select_tag&&Ot(a,{multiple:"multiple"}),e.placeholder&&Ot(n,{placeholder:e.placeholder}),!e.splitOn&&e.delimiter&&(e.splitOn=new RegExp("\\s*"+A(e.delimiter)+"+\\s*")),e.load&&e.loadThrottle&&(e.load=lt(e.load,e.loadThrottle)),dt(i,"mousemove",(()=>{t.ignoreHover=!1})),dt(i,"mouseenter",(e=>{var n=Tt(e.target,"[data-selectable]",i);n&&t.onOptionHover(e,n)}),{capture:!0}),dt(i,"click",(e=>{const n=Tt(e.target,"[data-selectable]");n&&(t.onOptionSelect(e,n),ut(e,!0))})),dt(s,"click",(e=>{var i=Tt(e.target,"[data-ts-item]",s);i&&t.onItemSelect(e,i)?ut(e,!0):""==n.value&&(t.onClick(),ut(e,!0))})),dt(l,"keydown",(e=>t.onKeyDown(e))),dt(n,"keypress",(e=>t.onKeyPress(e))),dt(n,"input",(e=>t.onInput(e))),dt(l,"blur",(e=>t.onBlur(e))),dt(l,"focus",(e=>t.onFocus(e))),dt(n,"paste",(e=>t.onPaste(e)));const f=e=>{const o=e.composedPath()[0];if(!r.contains(o)&&!i.contains(o))return t.isFocused&&t.blur(),void t.inputState();o==n&&t.isOpen?e.stopPropagation():ut(e,!0)},g=()=>{t.isOpen&&t.positionDropdown()};dt(document,"mousedown",f),dt(window,"scroll",g,c),dt(window,"resize",g,c),this._destroy=()=>{document.removeEventListener("mousedown",f),window.removeEventListener("scroll",g),window.removeEventListener("resize",g),p&&p.removeEventListener("click",m)},this.revertSettings={innerHTML:a.innerHTML,tabIndex:a.tabIndex},a.tabIndex=-1,a.insertAdjacentElement("afterend",t.wrapper),t.sync(!1),e.items=[],delete e.optgroups,delete e.options,dt(a,"invalid",(()=>{t.isValid&&(t.isValid=!1,t.isInvalid=!0,t.refreshState())})),t.updateOriginalInput(),t.refreshItems(),t.close(!1),t.inputState(),t.isSetup=!0,a.disabled?t.disable():a.readOnly?t.setReadOnly(!0):t.enable(),t.on("change",this.onChange),wt(a,"tomselected","ts-hidden-accessible"),t.trigger("initialize"),!0===e.preload&&t.preload()}setupOptions(t=[],e=[]){this.addOptions(t),gt(e,(t=>{this.registerOptionGroup(t)}))}setupTemplates(){var t=this,e=t.settings.labelField,n=t.settings.optgroupLabelField,i={optgroup:t=>{let e=document.createElement("div");return e.className="optgroup",e.appendChild(t.options),e},optgroup_header:(t,e)=>'
'+e(t[n])+"
",option:(t,n)=>"
"+n(t[e])+"
",item:(t,n)=>"
"+n(t[e])+"
",option_create:(t,e)=>'
Add '+e(t.input)+"…
",no_results:()=>'
No results found
',loading:()=>'
',not_loading:()=>{},dropdown:()=>"
"};t.settings.render=Object.assign({},i,t.settings.render)}setupCallbacks(){var t,e,n={initialize:"onInitialize",change:"onChange",item_add:"onItemAdd",item_remove:"onItemRemove",item_select:"onItemSelect",clear:"onClear",option_add:"onOptionAdd",option_remove:"onOptionRemove",option_clear:"onOptionClear",optgroup_add:"onOptionGroupAdd",optgroup_remove:"onOptionGroupRemove",optgroup_clear:"onOptionGroupClear",dropdown_open:"onDropdownOpen",dropdown_close:"onDropdownClose",type:"onType",load:"onLoad",focus:"onFocus",blur:"onBlur"};for(t in n)(e=this.settings[n[t]])&&this.on(t,e)}sync(t=!0){const e=this,n=t?It(e.input,{delimiter:e.settings.delimiter}):e.settings;e.setupOptions(n.options,n.optgroups),e.setValue(n.items||[],!0),e.lastQuery=null}onClick(){var t=this;if(t.activeItems.length>0)return t.clearActiveItems(),void t.focus();t.isFocused&&t.isOpen?t.blur():t.focus()}onMouseDown(){}onChange(){bt(this.input,"input"),bt(this.input,"change")}onPaste(t){var e=this;e.isInputHidden||e.isLocked?ut(t):e.settings.splitOn&&setTimeout((()=>{var t=e.inputValue();if(t.match(e.settings.splitOn)){var n=t.trim().split(e.settings.splitOn);gt(n,(t=>{rt(t)&&(this.options[t]?e.addItem(t):e.createItem(t))}))}}),0)}onKeyPress(t){var e=this;if(!e.isLocked){var n=String.fromCharCode(t.keyCode||t.which);return e.settings.create&&"multi"===e.settings.mode&&n===e.settings.delimiter?(e.createItem(),void ut(t)):void 0}ut(t)}onKeyDown(t){var e=this;if(e.ignoreHover=!0,e.isLocked)9!==t.keyCode&&ut(t);else{switch(t.keyCode){case 65:if(ht(Mt,t)&&""==e.control_input.value)return ut(t),void e.selectAll();break;case 27:return e.isOpen&&(ut(t,!0),e.close()),void e.clearActiveItems();case 40:if(!e.isOpen&&e.hasOptions)e.open();else if(e.activeOption){let t=e.getAdjacent(e.activeOption,1);t&&e.setActiveOption(t)}return void ut(t);case 38:if(e.activeOption){let t=e.getAdjacent(e.activeOption,-1);t&&e.setActiveOption(t)}return void ut(t);case 13:return void(e.canSelect(e.activeOption)?(e.onOptionSelect(t,e.activeOption),ut(t)):(e.settings.create&&e.createItem()||document.activeElement==e.control_input&&e.isOpen)&&ut(t));case 37:return void e.advanceSelection(-1,t);case 39:return void e.advanceSelection(1,t);case 9:return void(e.settings.selectOnTab&&(e.canSelect(e.activeOption)&&(e.onOptionSelect(t,e.activeOption),ut(t)),e.settings.create&&e.createItem()&&ut(t)));case 8:case 46:return void e.deleteSelection(t)}e.isInputHidden&&!ht(Mt,t)&&ut(t)}}onInput(t){if(this.isLocked)return;const e=this.inputValue();this.lastValue!==e&&(this.lastValue=e,""!=e?(this.refreshTimeout&&window.clearTimeout(this.refreshTimeout),this.refreshTimeout=((t,e)=>e>0?window.setTimeout(t,e):(t.call(null),null))((()=>{this.refreshTimeout=null,this._onInput()}),this.settings.refreshThrottle)):this._onInput())}_onInput(){const t=this.lastValue;this.settings.shouldLoad.call(this,t)&&this.load(t),this.refreshOptions(),this.trigger("type",t)}onOptionHover(t,e){this.ignoreHover||this.setActiveOption(e,!1)}onFocus(t){var e=this,n=e.isFocused;if(e.isDisabled||e.isReadOnly)return e.blur(),void ut(t);e.ignoreFocus||(e.isFocused=!0,"focus"===e.settings.preload&&e.preload(),n||e.trigger("focus"),e.activeItems.length||(e.inputState(),e.refreshOptions(!!e.settings.openOnFocus)),e.refreshState())}onBlur(t){if(!1!==document.hasFocus()){var e=this;if(e.isFocused){e.isFocused=!1,e.ignoreFocus=!1;var n=()=>{e.close(),e.setActiveItem(),e.setCaret(e.items.length),e.trigger("blur")};e.settings.create&&e.settings.createOnBlur?e.createItem(null,n):n()}}}onOptionSelect(t,e){var n,i=this;e.parentElement&&e.parentElement.matches("[data-disabled]")||(e.classList.contains("create")?i.createItem(null,(()=>{i.settings.closeAfterSelect&&i.close()})):void 0!==(n=e.dataset.value)&&(i.lastQuery=null,i.addItem(n),i.settings.closeAfterSelect&&i.close(),!i.settings.hideSelected&&t.type&&/click/.test(t.type)&&i.setActiveOption(e)))}canSelect(t){return!!(this.isOpen&&t&&this.dropdown_content.contains(t))}onItemSelect(t,e){var n=this;return!n.isLocked&&"multi"===n.settings.mode&&(ut(t),n.setActiveItem(e,t),!0)}canLoad(t){return!!this.settings.load&&!this.loadedSearches.hasOwnProperty(t)}load(t){const e=this;if(!e.canLoad(t))return;wt(e.wrapper,e.settings.loadingClass),e.loading++;const n=e.loadCallback.bind(e);e.settings.load.call(e,t,n)}loadCallback(t,e){const n=this;n.loading=Math.max(n.loading-1,0),n.lastQuery=null,n.clearActiveOption(),n.setupOptions(t,e),n.refreshOptions(n.isFocused&&!n.isInputHidden),n.loading||kt(n.wrapper,n.settings.loadingClass),n.trigger("load",t,e)}preload(){var t=this.wrapper.classList;t.contains("preloaded")||(t.add("preloaded"),this.load(""))}setTextboxValue(t=""){var e=this.control_input;e.value!==t&&(e.value=t,bt(e,"update"),this.lastValue=t)}getValue(){return this.is_select_tag&&this.input.hasAttribute("multiple")?this.items:this.items.join(this.settings.delimiter)}setValue(t,e){ct(this,e?[]:["change"],(()=>{this.clear(e),this.addItems(t,e)}))}setMaxItems(t){0===t&&(t=null),this.settings.maxItems=t,this.refreshState()}setActiveItem(t,e){var n,i,o,r,s,a,l=this;if("single"!==l.settings.mode){if(!t)return l.clearActiveItems(),void(l.isFocused&&l.inputState());if("click"===(n=e&&e.type.toLowerCase())&&ht("shiftKey",e)&&l.activeItems.length){for(a=l.getLastActive(),(o=Array.prototype.indexOf.call(l.control.children,a))>(r=Array.prototype.indexOf.call(l.control.children,t))&&(s=o,o=r,r=s),i=o;i<=r;i++)t=l.control.children[i],-1===l.activeItems.indexOf(t)&&l.setActiveItemClass(t);ut(e)}else"click"===n&&ht(Mt,e)||"keydown"===n&&ht("shiftKey",e)?t.classList.contains("active")?l.removeActiveItem(t):l.setActiveItemClass(t):(l.clearActiveItems(),l.setActiveItemClass(t));l.inputState(),l.isFocused||l.focus()}}setActiveItemClass(t){const e=this,n=e.control.querySelector(".last-active");n&&kt(n,"last-active"),wt(t,"active last-active"),e.trigger("item_select",t),-1==e.activeItems.indexOf(t)&&e.activeItems.push(t)}removeActiveItem(t){var e=this.activeItems.indexOf(t);this.activeItems.splice(e,1),kt(t,"active")}clearActiveItems(){kt(this.activeItems,"active"),this.activeItems=[]}setActiveOption(t,e=!0){t!==this.activeOption&&(this.clearActiveOption(),t&&(this.activeOption=t,Ot(this.focus_node,{"aria-activedescendant":t.getAttribute("id")}),Ot(t,{"aria-selected":"true"}),wt(t,"active"),e&&this.scrollToOption(t)))}scrollToOption(t,e){if(!t)return;const n=this.dropdown_content,i=n.clientHeight,o=n.scrollTop||0,r=t.offsetHeight,s=t.getBoundingClientRect().top-n.getBoundingClientRect().top+o;s+r>i+o?this.scroll(s-i+r,e):s{t.setActiveItemClass(e)})))}inputState(){var t=this;t.control.contains(t.control_input)&&(Ot(t.control_input,{placeholder:t.settings.placeholder}),t.activeItems.length>0||!t.isFocused&&t.settings.hidePlaceholder&&t.items.length>0?(t.setTextboxValue(),t.isInputHidden=!0):(t.settings.hidePlaceholder&&t.items.length>0&&Ot(t.control_input,{placeholder:""}),t.isInputHidden=!1),t.wrapper.classList.toggle("input-hidden",t.isInputHidden))}inputValue(){return this.control_input.value.trim()}focus(){var t=this;t.isDisabled||t.isReadOnly||(t.ignoreFocus=!0,t.control_input.offsetWidth?t.control_input.focus():t.focus_node.focus(),setTimeout((()=>{t.ignoreFocus=!1,t.onFocus()}),0))}blur(){this.focus_node.blur(),this.onBlur()}getScoreFunction(t){return this.sifter.getScoreFunction(t,this.getSearchOptions())}getSearchOptions(){var t=this.settings,e=t.sortField;return"string"==typeof t.sortField&&(e=[{field:t.sortField}]),{fields:t.searchField,conjunction:t.searchConjunction,sort:e,nesting:t.nesting}}search(t){var e,n,i=this,o=this.getSearchOptions();if(i.settings.score&&"function"!=typeof(n=i.settings.score.call(i,t)))throw new Error('Tom Select "score" setting must be a function that returns a function');return t!==i.lastQuery?(i.lastQuery=t,e=i.sifter.search(t,Object.assign(o,{score:n})),i.currentResults=e):e=Object.assign({},i.currentResults),i.settings.hideSelected&&(e.items=e.items.filter((t=>{let e=rt(t.id);return!(e&&-1!==i.items.indexOf(e))}))),e}refreshOptions(t=!0){var e,n,i,o,r,s,a,l,c,u;const d={},h=[];var p=this,m=p.inputValue();const f=m===p.lastQuery||""==m&&null==p.lastQuery;var g=p.search(m),v=null,y=p.settings.shouldOpen||!1,b=p.dropdown_content;f&&(v=p.activeOption)&&(c=v.closest("[data-group]")),o=g.items.length,"number"==typeof p.settings.maxOptions&&(o=Math.min(o,p.settings.maxOptions)),o>0&&(y=!0);const _=(t,e)=>{let n=d[t];if(void 0!==n){let t=h[n];if(void 0!==t)return[n,t.fragment]}let i=document.createDocumentFragment();return n=h.length,h.push({fragment:i,order:e,optgroup:t}),[n,i]};for(e=0;e0&&(u=u.cloneNode(!0),Ot(u,{id:a.$id+"-clone-"+n,"aria-selected":null}),u.classList.add("ts-cloned"),kt(u,"active"),p.activeOption&&p.activeOption.dataset.value==o&&c&&c.dataset.group===r.toString()&&(v=u)),l.appendChild(u),""!=r&&(d[r]=i)}}var w;p.settings.lockOptgroupOrder&&h.sort(((t,e)=>t.order-e.order)),a=document.createDocumentFragment(),gt(h,(t=>{let e=t.fragment,n=t.optgroup;if(!e||!e.children.length)return;let i=p.optgroups[n];if(void 0!==i){let t=document.createDocumentFragment(),n=p.render("optgroup_header",i);ft(t,n),ft(t,e);let o=p.render("optgroup",{group:i,options:t});ft(a,o)}else ft(a,e)})),b.innerHTML="",ft(b,a),p.settings.highlight&&(w=b.querySelectorAll("span.highlight"),Array.prototype.forEach.call(w,(function(t){var e=t.parentNode;e.replaceChild(t.firstChild,t),e.normalize()})),g.query.length&&g.tokens.length&>(g.tokens,(t=>{Lt(b,t.regex)})));var k=t=>{let e=p.render(t,{input:m});return e&&(y=!0,b.insertBefore(e,b.firstChild)),e};if(p.loading?k("loading"):p.settings.shouldLoad.call(p,m)?0===g.items.length&&k("no_results"):k("not_loading"),(l=p.canCreate(m))&&(u=k("option_create")),p.hasOptions=g.items.length>0||l,y){if(g.items.length>0){if(v||"single"!==p.settings.mode||null==p.items[0]||(v=p.getOption(p.items[0])),!b.contains(v)){let t=0;u&&!p.settings.addPrecedence&&(t=1),v=p.selectable()[t]}}else u&&(v=u);t&&!p.isOpen&&(p.open(),p.scrollToOption(v,"auto")),p.setActiveOption(v)}else p.clearActiveOption(),t&&p.isOpen&&p.close(!1)}selectable(){return this.dropdown_content.querySelectorAll("[data-selectable]")}addOption(t,e=!1){const n=this;if(Array.isArray(t))return n.addOptions(t,e),!1;const i=rt(t[n.settings.valueField]);return null!==i&&!n.options.hasOwnProperty(i)&&(t.$order=t.$order||++n.order,t.$id=n.inputId+"-opt-"+t.$order,n.options[i]=t,n.lastQuery=null,e&&(n.userOptions[i]=e,n.trigger("option_add",i,t)),i)}addOptions(t,e=!1){gt(t,(t=>{this.addOption(t,e)}))}registerOption(t){return this.addOption(t)}registerOptionGroup(t){var e=rt(t[this.settings.optgroupValueField]);return null!==e&&(t.$order=t.$order||++this.order,this.optgroups[e]=t,e)}addOptionGroup(t,e){var n;e[this.settings.optgroupValueField]=t,(n=this.registerOptionGroup(e))&&this.trigger("optgroup_add",n,e)}removeOptionGroup(t){this.optgroups.hasOwnProperty(t)&&(delete this.optgroups[t],this.clearCache(),this.trigger("optgroup_remove",t))}clearOptionGroups(){this.optgroups={},this.clearCache(),this.trigger("optgroup_clear")}updateOption(t,e){const n=this;var i,o;const r=rt(t),s=rt(e[n.settings.valueField]);if(null===r)return;const a=n.options[r];if(null==a)return;if("string"!=typeof s)throw new Error("Value must be set in option data");const l=n.getOption(r),c=n.getItem(r);if(e.$order=e.$order||a.$order,delete n.options[r],n.uncacheValue(s),n.options[s]=e,l){if(n.dropdown_content.contains(l)){const t=n._render("option",e);Ct(l,t),n.activeOption===l&&n.setActiveOption(t)}l.remove()}c&&(-1!==(o=n.items.indexOf(r))&&n.items.splice(o,1,s),i=n._render("item",e),c.classList.contains("active")&&wt(i,"active"),Ct(c,i)),n.lastQuery=null}removeOption(t,e){const n=this;t=st(t),n.uncacheValue(t),delete n.userOptions[t],delete n.options[t],n.lastQuery=null,n.trigger("option_remove",t),n.removeItem(t,e)}clearOptions(t){const e=(t||this.clearFilter).bind(this);this.loadedSearches={},this.userOptions={},this.clearCache();const n={};gt(this.options,((t,i)=>{e(t,i)&&(n[i]=t)})),this.options=this.sifter.items=n,this.lastQuery=null,this.trigger("option_clear")}clearFilter(t,e){return this.items.indexOf(e)>=0}getOption(t,e=!1){const n=rt(t);if(null===n)return null;const i=this.options[n];if(null!=i){if(i.$div)return i.$div;if(e)return this._render("option",i)}return null}getAdjacent(t,e,n="option"){var i;if(!t)return null;i="item"==n?this.controlChildren():this.dropdown_content.querySelectorAll("[data-selectable]");for(let n=0;n0?i[n+1]:i[n-1];return null}getItem(t){if("object"==typeof t)return t;var e=rt(t);return null!==e?this.control.querySelector(`[data-value="${mt(e)}"]`):null}addItems(t,e){var n=this,i=Array.isArray(t)?t:[t];const o=(i=i.filter((t=>-1===n.items.indexOf(t))))[i.length-1];i.forEach((t=>{n.isPending=t!==o,n.addItem(t,e)}))}addItem(t,e){ct(this,e?[]:["change","dropdown_close"],(()=>{var n,i;const o=this,r=o.settings.mode,s=rt(t);if((!s||-1===o.items.indexOf(s)||("single"===r&&o.close(),"single"!==r&&o.settings.duplicates))&&null!==s&&o.options.hasOwnProperty(s)&&("single"===r&&o.clear(e),"multi"!==r||!o.isFull())){if(n=o._render("item",o.options[s]),o.control.contains(n)&&(n=n.cloneNode(!0)),i=o.isFull(),o.items.splice(o.caretPos,0,s),o.insertAtCaret(n),o.isSetup){if(!o.isPending&&o.settings.hideSelected){let t=o.getOption(s),e=o.getAdjacent(t,1);e&&o.setActiveOption(e)}o.isPending||o.settings.closeAfterSelect||o.refreshOptions(o.isFocused&&"single"!==r),0!=o.settings.closeAfterSelect&&o.isFull()?o.close():o.isPending||o.positionDropdown(),o.trigger("item_add",s,n),o.isPending||o.updateOriginalInput({silent:e})}(!o.isPending||!i&&o.isFull())&&(o.inputState(),o.refreshState())}}))}removeItem(t=null,e){const n=this;if(!(t=n.getItem(t)))return;var i,o;const r=t.dataset.value;i=xt(t),t.remove(),t.classList.contains("active")&&(o=n.activeItems.indexOf(t),n.activeItems.splice(o,1),kt(t,"active")),n.items.splice(i,1),n.lastQuery=null,!n.settings.persist&&n.userOptions.hasOwnProperty(r)&&n.removeOption(r,e),i{})){3===arguments.length&&(e=arguments[2]),"function"!=typeof e&&(e=()=>{});var n,i=this,o=i.caretPos;if(t=t||i.inputValue(),!i.canCreate(t))return e(),!1;i.lock();var r=!1,s=t=>{if(i.unlock(),!t||"object"!=typeof t)return e();var n=rt(t[i.settings.valueField]);if("string"!=typeof n)return e();i.setTextboxValue(),i.addOption(t,!0),i.setCaret(o),i.addItem(n),e(t),r=!0};return n="function"==typeof i.settings.create?i.settings.create.call(this,t,s):{[i.settings.labelField]:t,[i.settings.valueField]:t},r||s(n),!0}refreshItems(){var t=this;t.lastQuery=null,t.isSetup&&t.addItems(t.items),t.updateOriginalInput(),t.refreshState()}refreshState(){const t=this;t.refreshValidityState();const e=t.isFull(),n=t.isLocked;t.wrapper.classList.toggle("rtl",t.rtl);const i=t.wrapper.classList;var o;i.toggle("focus",t.isFocused),i.toggle("disabled",t.isDisabled),i.toggle("readonly",t.isReadOnly),i.toggle("required",t.isRequired),i.toggle("invalid",!t.isValid),i.toggle("locked",n),i.toggle("full",e),i.toggle("input-active",t.isFocused&&!t.isInputHidden),i.toggle("dropdown-active",t.isOpen),i.toggle("has-options",(o=t.options,0===Object.keys(o).length)),i.toggle("has-items",t.items.length>0)}refreshValidityState(){var t=this;t.input.validity&&(t.isValid=t.input.validity.valid,t.isInvalid=!t.isValid)}isFull(){return null!==this.settings.maxItems&&this.items.length>=this.settings.maxItems}updateOriginalInput(t={}){const e=this;var n,i;const o=e.input.querySelector('option[value=""]');if(e.is_select_tag){const r=[],s=e.input.querySelectorAll("option:checked").length;function a(t,n,i){return t||(t=vt('")),t!=o&&e.input.append(t),r.push(t),(t!=o||s>0)&&(t.selected=!0),t}e.input.querySelectorAll("option:checked").forEach((t=>{t.selected=!1})),0==e.items.length&&"single"==e.settings.mode?a(o,"",""):e.items.forEach((t=>{if(n=e.options[t],i=n[e.settings.labelField]||"",r.includes(n.$option)){a(e.input.querySelector(`option[value="${mt(t)}"]:not(:checked)`),t,i)}else n.$option=a(n.$option,t,i)}))}else e.input.value=e.getValue();e.isSetup&&(t.silent||e.trigger("change",e.getValue()))}open(){var t=this;t.isLocked||t.isOpen||"multi"===t.settings.mode&&t.isFull()||(t.isOpen=!0,Ot(t.focus_node,{"aria-expanded":"true"}),t.refreshState(),_t(t.dropdown,{visibility:"hidden",display:"block"}),t.positionDropdown(),_t(t.dropdown,{visibility:"visible",display:"block"}),t.focus(),t.trigger("dropdown_open",t.dropdown))}close(t=!0){var e=this,n=e.isOpen;t&&(e.setTextboxValue(),"single"===e.settings.mode&&e.items.length&&e.inputState()),e.isOpen=!1,Ot(e.focus_node,{"aria-expanded":"false"}),_t(e.dropdown,{display:"none"}),e.settings.hideSelected&&e.clearActiveOption(),e.refreshState(),n&&e.trigger("dropdown_close",e.dropdown)}positionDropdown(){if("body"===this.settings.dropdownParent){var t=this.control,e=t.getBoundingClientRect(),n=t.offsetHeight+e.top+window.scrollY,i=e.left+window.scrollX;_t(this.dropdown,{width:e.width+"px",top:n+"px",left:i+"px"})}}clear(t){var e=this;if(e.items.length){var n=e.controlChildren();gt(n,(t=>{e.removeItem(t,!0)})),e.inputState(),t||e.updateOriginalInput(),e.trigger("clear")}}insertAtCaret(t){const e=this,n=e.caretPos,i=e.control;i.insertBefore(t,i.children[n]||null),e.setCaret(n+1)}deleteSelection(t){var e,n,i,o,r,s=this;e=t&&8===t.keyCode?-1:1,n={start:(r=s.control_input).selectionStart||0,length:(r.selectionEnd||0)-(r.selectionStart||0)};const a=[];if(s.activeItems.length)o=St(s.activeItems,e),i=xt(o),e>0&&i++,gt(s.activeItems,(t=>a.push(t)));else if((s.isFocused||"single"===s.settings.mode)&&s.items.length){const t=s.controlChildren();let i;e<0&&0===n.start&&0===n.length?i=t[s.caretPos-1]:e>0&&n.start===s.inputValue().length&&(i=t[s.caretPos]),void 0!==i&&a.push(i)}if(!s.shouldDelete(a,t))return!1;for(ut(t,!0),void 0!==i&&s.setCaret(i);a.length;)s.removeItem(a.pop());return s.inputState(),s.positionDropdown(),s.refreshOptions(!1),!0}shouldDelete(t,e){const n=t.map((t=>t.dataset.value));return!(!n.length||"function"==typeof this.settings.onDelete&&!1===this.settings.onDelete(n,e))}advanceSelection(t,e){var n,i,o=this;o.rtl&&(t*=-1),o.inputValue().length||(ht(Mt,e)||ht("shiftKey",e)?(i=(n=o.getLastActive(t))?n.classList.contains("active")?o.getAdjacent(n,t,"item"):n:t>0?o.control_input.nextElementSibling:o.control_input.previousElementSibling)&&(i.classList.contains("active")&&o.removeActiveItem(n),o.setActiveItemClass(i)):o.moveCaret(t))}moveCaret(t){}getLastActive(t){let e=this.control.querySelector(".last-active");if(e)return e;var n=this.control.querySelectorAll(".active");return n?St(n,t):void 0}setCaret(t){this.caretPos=this.items.length}controlChildren(){return Array.from(this.control.querySelectorAll("[data-ts-item]"))}lock(){this.setLocked(!0)}unlock(){this.setLocked(!1)}setLocked(t=this.isReadOnly||this.isDisabled){this.isLocked=t,this.refreshState()}disable(){this.setDisabled(!0),this.close()}enable(){this.setDisabled(!1)}setDisabled(t){this.focus_node.tabIndex=t?-1:this.tabIndex,this.isDisabled=t,this.input.disabled=t,this.control_input.disabled=t,this.setLocked()}setReadOnly(t){this.isReadOnly=t,this.input.readOnly=t,this.control_input.readOnly=t,this.setLocked()}destroy(){var t=this,e=t.revertSettings;t.trigger("destroy"),t.off(),t.wrapper.remove(),t.dropdown.remove(),t.input.innerHTML=e.innerHTML,t.input.tabIndex=e.tabIndex,kt(t.input,"tomselected","ts-hidden-accessible"),t._destroy(),delete t.input.tomselect}render(t,e){var n,i;const o=this;if("function"!=typeof this.settings.render[t])return null;if(!(i=o.settings.render[t].call(this,e,at)))return null;if(i=vt(i),"option"===t||"option_create"===t?e[o.settings.disabledField]?Ot(i,{"aria-disabled":"true"}):Ot(i,{"data-selectable":""}):"optgroup"===t&&(n=e.group[o.settings.optgroupValueField],Ot(i,{"data-group":n}),e.group[o.settings.disabledField]&&Ot(i,{"data-disabled":""})),"option"===t||"item"===t){const n=st(e[o.settings.valueField]);Ot(i,{"data-value":n}),"item"===t?(wt(i,o.settings.itemClass),Ot(i,{"data-ts-item":""})):(wt(i,o.settings.optionClass),Ot(i,{role:"option",id:e.$id}),e.$div=i,o.options[n]=e)}return i}_render(t,e){const n=this.render(t,e);if(null==n)throw"HTMLElement expected";return n}clearCache(){gt(this.options,(t=>{t.$div&&(t.$div.remove(),delete t.$div)}))}uncacheValue(t){const e=this.getOption(t);e&&e.remove()}canCreate(t){return this.settings.create&&t.length>0&&this.settings.createFilter.call(this,t)}hook(t,e,n){var i=this,o=i[e];i[e]=function(){var e,r;return"after"===t&&(e=o.apply(i,arguments)),r=n.apply(i,arguments),"instead"===t?r:("before"===t&&(e=o.apply(i,arguments)),e)}}}const Ft=t=>"boolean"==typeof t?t?"1":"0":t+"",jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},qt=t=>"string"==typeof t&&t.indexOf("<")>-1;const Ht=t=>"string"==typeof t&&t.indexOf("<")>-1;const Vt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Rt=t=>"string"==typeof t&&t.indexOf("<")>-1,Bt=(t,e)=>{((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(e,((e,n)=>{null==e?t.removeAttribute(n):t.setAttribute(n,""+e)}))};const $t=t=>"string"==typeof t&&t.indexOf("<")>-1;const Wt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Yt=t=>(Array.isArray(t)||(t=[t]),t);const zt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Ut(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},Ut=t=>"string"==typeof t&&t.indexOf("<")>-1,Zt=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},Xt=t=>(Array.isArray(t)||(t=[t]),t);const Kt=(t,e,n,i)=>{t.addEventListener(e,n,i)};const Jt=(t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())},Gt=(t,e,n,i)=>{t.addEventListener(e,n,i)},Qt=t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(te(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)},te=t=>"string"==typeof t&&t.indexOf("<")>-1;const ee=t=>{var e=[];return((t,e)=>{if(Array.isArray(t))t.forEach(e);else for(var n in t)t.hasOwnProperty(n)&&e(t[n],n)})(t,(t=>{"string"==typeof t&&(t=t.trim().split(/[\t\n\f\r\s]/)),Array.isArray(t)&&(e=e.concat(t))})),e.filter(Boolean)},ne=t=>(Array.isArray(t)||(t=[t]),t);Pt.define("change_listener",(function(){var t,e,n,i;t=this.input,e="change",n=()=>{this.sync()},t.addEventListener(e,n,i)})),Pt.define("checkbox_options",(function(t){var e=this,n=e.onOptionSelect;e.settings.hideSelected=!1;const i=Object.assign({className:"tomselect-checkbox",checkedClassNames:void 0,uncheckedClassNames:void 0},t);var o=function(t,e){e?(t.checked=!0,i.uncheckedClassNames&&t.classList.remove(...i.uncheckedClassNames),i.checkedClassNames&&t.classList.add(...i.checkedClassNames)):(t.checked=!1,i.checkedClassNames&&t.classList.remove(...i.checkedClassNames),i.uncheckedClassNames&&t.classList.add(...i.uncheckedClassNames))},r=function(t){setTimeout((()=>{var e=t.querySelector("input."+i.className);e instanceof HTMLInputElement&&o(e,t.classList.contains("selected"))}),1)};e.hook("after","setupTemplates",(()=>{var t=e.settings.render.option;e.settings.render.option=(n,r)=>{var s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(qt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(t.call(e,n,r)),a=document.createElement("input");i.className&&a.classList.add(i.className),a.addEventListener("click",(function(t){jt(t)})),a.type="checkbox";const l=null==(c=n[e.settings.valueField])?null:Ft(c);var c;return o(a,!!(l&&e.items.indexOf(l)>-1)),s.prepend(a),s}})),e.on("item_remove",(t=>{var n=e.getOption(t);n&&(n.classList.remove("selected"),r(n))})),e.on("item_add",(t=>{var n=e.getOption(t);n&&r(n)})),e.hook("instead","onOptionSelect",((t,i)=>{if(i.classList.contains("selected"))return i.classList.remove("selected"),e.removeItem(i.dataset.value),e.refreshOptions(),void jt(t,!0);n.call(e,t,i),r(i)}))})),Pt.define("clear_button",(function(t){const e=this,n=Object.assign({className:"clear-button",title:"Clear All",html:t=>`
⨯
`},t);e.on("initialize",(()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Ht(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n));t.addEventListener("click",(t=>{e.isLocked||(e.clear(),"single"===e.settings.mode&&e.settings.allowEmptyOption&&e.addItem(""),t.preventDefault(),t.stopPropagation())})),e.control.appendChild(t)}))})),Pt.define("drag_drop",(function(){var t=this;if("multi"!==t.settings.mode)return;var e=t.lock,n=t.unlock;let i,o=!0;t.hook("after","setupTemplates",(()=>{var e=t.settings.render.item;t.settings.render.item=(n,r)=>{const s=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if(Rt(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(e.call(t,n,r));Bt(s,{draggable:"true"});const a=t=>{t.preventDefault(),s.classList.add("ts-drag-over"),l(s,i)},l=(t,e)=>{var n,i,o;void 0!==e&&(((t,e)=>{do{var n;if(t==(e=null==(n=e)?void 0:n.previousElementSibling))return!0}while(e&&e.previousElementSibling);return!1})(e,s)?(i=e,null==(o=(n=t).parentNode)||o.insertBefore(i,n.nextSibling)):((t,e)=>{var n;null==(n=t.parentNode)||n.insertBefore(e,t)})(t,e))};return Vt(s,"mousedown",(t=>{o||((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t),t.stopPropagation()})),Vt(s,"dragstart",(t=>{i=s,setTimeout((()=>{s.classList.add("ts-dragging")}),0)})),Vt(s,"dragenter",a),Vt(s,"dragover",a),Vt(s,"dragleave",(()=>{s.classList.remove("ts-drag-over")})),Vt(s,"dragend",(()=>{var e;document.querySelectorAll(".ts-drag-over").forEach((t=>t.classList.remove("ts-drag-over"))),null==(e=i)||e.classList.remove("ts-dragging"),i=void 0;var n=[];t.control.querySelectorAll("[data-value]").forEach((t=>{if(t.dataset.value){let e=t.dataset.value;e&&n.push(e)}})),t.setValue(n)})),s}})),t.hook("instead","lock",(()=>(o=!1,e.call(t)))),t.hook("instead","unlock",(()=>(o=!0,n.call(t))))})),Pt.define("dropdown_header",(function(t){const e=this,n=Object.assign({title:"Untitled",headerClass:"dropdown-header",titleRowClass:"dropdown-header-title",labelClass:"dropdown-header-label",closeClass:"dropdown-header-close",html:t=>'
'+t.title+'×
'},t);e.on("initialize",(()=>{var t=(t=>{if(t.jquery)return t[0];if(t instanceof HTMLElement)return t;if($t(t)){var e=document.createElement("template");return e.innerHTML=t.trim(),e.content.firstChild}return document.querySelector(t)})(n.html(n)),i=t.querySelector("."+n.closeClass);i&&i.addEventListener("click",(t=>{((t,e=!1)=>{t&&(t.preventDefault(),e&&t.stopPropagation())})(t,!0),e.close()})),e.dropdown.insertBefore(t,e.dropdown.firstChild)}))})),Pt.define("caret_position",(function(){var t=this;t.hook("instead","setCaret",(e=>{"single"!==t.settings.mode&&t.control.contains(t.control_input)?(e=Math.max(0,Math.min(t.items.length,e)))==t.caretPos||t.isPending||t.controlChildren().forEach(((n,i)=>{i{if(!t.isFocused)return;const n=t.getLastActive(e);if(n){const i=((t,e)=>{if(!t)return-1;e=e||t.nodeName;for(var n=0;t=t.previousElementSibling;)t.matches(e)&&n++;return n})(n);t.setCaret(e>0?i+1:i),t.setActiveItem(),((t,...e)=>{var n=Wt(e);(t=Yt(t)).map((t=>{n.map((e=>{t.classList.remove(e)}))}))})(n,"last-active")}else t.setCaret(t.caretPos+e)}))})),Pt.define("dropdown_input",(function(){const t=this;t.settings.shouldOpen=!0,t.hook("before","setup",(()=>{t.focus_node=t.control,((t,...e)=>{var n=Zt(e);(t=Xt(t)).map((t=>{n.map((e=>{t.classList.add(e)}))}))})(t.control_input,"dropdown-input");const e=zt(' {% endblock %} diff --git a/tests/API/APIControllerBaseTestCase.php b/tests/API/APIControllerBaseTestCase.php index 193bf6c44..22b689d51 100644 --- a/tests/API/APIControllerBaseTestCase.php +++ b/tests/API/APIControllerBaseTestCase.php @@ -214,7 +214,6 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase } /** - * @param Response $response * @param array|array $failedFields * @param bool $extraFields test for the error "This form should not contain extra fields" * @param array|array $globalError @@ -231,7 +230,7 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase } if (\count($globalError) > 0) { - self::assertArrayHasKey('errors', $result['errors']); + self::assertArrayHasKey('errors', $result['errors'], 'API response has no global errors, but expected ' . \count($globalError)); foreach ($globalError as $err) { self::assertTrue(\in_array($err, $result['errors']['errors']), 'Missing global validation error: ' . $err); // @phpstan-ignore binaryOp.invalid } @@ -327,24 +326,20 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase return [ 'id' => 'int', 'name' => 'string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'visible' => 'bool', ]; // embedded meta data case 'UserPreference': - return [ - 'name' => 'string', - 'value' => '@string', - ]; - case 'CustomerMeta': case 'ProjectMeta': case 'ActivityMeta': case 'TimesheetMeta': return [ 'name' => 'string', - 'value' => 'string', + 'value' => '@string', ]; // if a user is embedded in other objects @@ -356,9 +351,9 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'username' => 'string', 'email' => 'string', 'enabled' => 'bool', - 'apiToken' => 'bool', 'systemAccount' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'avatar' => '@string', 'alias' => '@string', 'accountNumber' => '@string', @@ -376,9 +371,9 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'username' => 'string', 'email' => 'string', 'enabled' => 'bool', - 'apiToken' => 'bool', 'systemAccount' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'avatar' => '@string', 'alias' => '@string', 'accountNumber' => '@string', @@ -402,7 +397,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase return [ 'id' => 'int', 'name' => 'string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', ]; // explicitly requested team @@ -410,7 +406,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase return [ 'id' => 'int', 'name' => 'string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'members' => ['result' => 'array', 'type' => 'TeamMember'], // TODO more info in entity than in collection 'customers' => ['result' => 'array', 'type' => '@Customer'], @@ -439,7 +436,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'number' => '@string', 'comment' => '@string', 'currency' => 'string', @@ -460,7 +458,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'boolean', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'number' => '@string', 'comment' => '@string', 'currency' => 'string', @@ -482,7 +481,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'number' => '@string', 'comment' => '@string', 'currency' => 'string', @@ -519,7 +519,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'customer' => 'int', 'number' => '@string', 'orderNumber' => '@string', @@ -538,7 +539,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'customer' => ['result' => 'object', 'type' => 'Customer'], 'number' => '@string', 'orderNumber' => '@string', @@ -557,7 +559,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'customer' => 'int', 'number' => '@string', 'orderNumber' => '@string', @@ -578,7 +581,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'name' => 'string', 'visible' => 'bool', 'billable' => 'bool', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'customer' => 'int', 'number' => '@string', 'orderNumber' => '@string', @@ -605,7 +609,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'billable' => 'bool', 'project' => '@int', 'number' => '@string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'], // since 2.45 'comment' => '@string', ]; @@ -618,7 +623,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'billable' => 'bool', 'project' => ['result' => 'object', 'type' => '@ProjectExpanded'], 'number' => '@string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'], // since 2.45 'comment' => '@string', ]; @@ -632,7 +638,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'billable' => 'bool', 'project' => '@int', 'number' => '@string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'], 'comment' => '@string', 'parentTitle' => '@string', @@ -648,7 +655,8 @@ abstract class APIControllerBaseTestCase extends AbstractControllerBaseTestCase 'billable' => 'bool', 'project' => '@int', 'number' => '@string', - 'color' => 'string', + 'color' => '@string', + 'color-safe' => 'string', 'metaFields' => ['result' => 'array', 'type' => 'ProjectMeta'], 'comment' => '@string', 'parentTitle' => '@string', diff --git a/tests/API/ActivityControllerTest.php b/tests/API/ActivityControllerTest.php index 44330b6ea..0c62cb159 100644 --- a/tests/API/ActivityControllerTest.php +++ b/tests/API/ActivityControllerTest.php @@ -244,7 +244,6 @@ class ActivityControllerTest extends APIControllerBaseTestCase self::assertIsArray($result); self::assertApiResponseTypeStructure('ActivityEntity', $result); - self::assertCount(14, array_keys($result)); self::assertNull($result['parentTitle']); self::assertNotEmpty($result['id']); self::assertIsArray($result['teams']); @@ -258,7 +257,8 @@ class ActivityControllerTest extends APIControllerBaseTestCase self::assertNull($result['budgetType']); self::assertNull($result['number']); self::assertEquals('Test comment', $result['comment']); - self::assertEquals('#5319e7', $result['color']); + self::assertNull($result['color']); + self::assertEquals('#5319e7', $result['color-safe']); self::assertTrue($result['visible']); self::assertTrue($result['billable']); } @@ -297,7 +297,7 @@ class ActivityControllerTest extends APIControllerBaseTestCase self::assertEquals('Test', $result['parentTitle']); self::assertNotEmpty($result['id']); self::assertIsArray($result['teams']); - self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => '#03A9F4']], $result['teams']); + self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null, 'color-safe' => '#03A9F4']], $result['teams']); self::assertIsArray($result['metaFields']); self::assertEquals([], $result['metaFields']); self::assertEquals('foo', $result['name']); diff --git a/tests/API/ApiDocControllerTest.php b/tests/API/ApiDocControllerTest.php index 5b4a5b73f..1f03fee8d 100644 --- a/tests/API/ApiDocControllerTest.php +++ b/tests/API/ApiDocControllerTest.php @@ -50,10 +50,10 @@ class ApiDocControllerTest extends AbstractControllerBaseTestCase $expectedKeys = ['Actions', 'Activity', 'Default', 'Customer', 'Project', 'Tag', 'Team', 'Timesheet', 'User', 'Invoice', 'Export']; $actual = array_keys($tags); - sort($actual); - sort($expectedKeys); - - self::assertEquals($expectedKeys, $actual, \sprintf('Expected %s sections in API docs, but found %s.', \count($actual), \count($expectedKeys))); + //dd($expectedKeys, $actual); + foreach ($expectedKeys as $expectedKey) { + self::assertTrue(\in_array($expectedKey, $actual), 'Expected API section is missing: ' . $expectedKey); + } $paths = [ '/api/actions/timesheet/{id}/{view}/{locale}', @@ -115,7 +115,9 @@ class ApiDocControllerTest extends AbstractControllerBaseTestCase self::assertEquals('1.1', $json['info']['version']); self::assertArrayHasKey('paths', $json); - self::assertEquals($paths, array_keys($json['paths'])); + foreach ($paths as $path) { + self::assertArrayHasKey($path, $json['paths'], 'Missing API endpoint: ' . $path); + } self::assertArrayHasKey('security', $json); self::assertEquals(['bearer' => []], $json['security'][0]); diff --git a/tests/API/Authentication/TokenAuthenticatorTest.php b/tests/API/Authentication/TokenAuthenticatorTest.php deleted file mode 100644 index 4689adc7f..000000000 --- a/tests/API/Authentication/TokenAuthenticatorTest.php +++ /dev/null @@ -1,168 +0,0 @@ -createMock(ApiUserRepository::class); - $passwordHasherFactory = $this->createMock(PasswordHasherFactoryInterface::class); - $passwordHasher = $this->createMock(PasswordHasherInterface::class); - $passwordHasher->method('verify')->willReturn($verify); - $passwordHasherFactory->method('getPasswordHasher')->willReturn($passwordHasher); - - return new TokenAuthenticator($userProvider, $passwordHasherFactory); - } - - public function testSupports(): void - { - $sut = $this->getSut(); - - // not supporting because /api path is not the beginning of the URL - $request = new Request([], [], [], [], [], ['REQUEST_URI' => 'dfghj/api/doc/dfghj']); - self::assertFalse($sut->supports($request)); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo']); - self::assertFalse($sut->supports($request)); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/doc']); - self::assertFalse($sut->supports($request)); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo', 'HTTP_X-AUTH-TOKEN' => 'bar']); - self::assertTrue($sut->supports($request)); - } - - public function testAuthenticateWithMissingAuthHeader(): void - { - $this->expectException(CustomUserMessageAuthenticationException::class); - $this->expectExceptionMessage('Authentication required, missing user header: X-AUTH-USER'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo']); - $sut->authenticate($request); - } - - public function testAuthenticateWithMissingToken(): void - { - $this->expectException(CustomUserMessageAuthenticationException::class); - $this->expectExceptionMessage('Authentication required, missing token header: X-AUTH-TOKEN'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo']); - $sut->authenticate($request); - } - - public function testAuthenticateWithEmptyToken(): void - { - $this->expectException(CustomUserMessageAuthenticationException::class); - $this->expectExceptionMessage('Authentication required, missing token header: X-AUTH-TOKEN'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo', 'HTTP_X-AUTH-TOKEN' => '']); - $sut->authenticate($request); - } - - public function testAuthenticateWithMissingUser(): void - { - $this->expectException(CustomUserMessageAuthenticationException::class); - $this->expectExceptionMessage('Authentication required, missing user header: X-AUTH-USER'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-TOKEN' => 'bar']); - $sut->authenticate($request); - } - - public function testAuthenticateWithEmptyUser(): void - { - $this->expectException(CustomUserMessageAuthenticationException::class); - $this->expectExceptionMessage('Authentication required, missing user header: X-AUTH-USER'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => '', 'HTTP_X-AUTH-TOKEN' => 'bar']); - $sut->authenticate($request); - } - - public function testAuthenticate(): void - { - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo2', 'HTTP_X-AUTH-TOKEN' => 'bar']); - $passport = $sut->authenticate($request); - $badge = $passport->getBadge(UserBadge::class); - self::assertInstanceOf(UserBadge::class, $badge); - self::assertEquals('foo2', $badge->getUserIdentifier()); - - $user = new User(); - $user->setApiToken('bar2'); - - $badge = $passport->getBadge(CustomCredentials::class); - self::assertInstanceOf(CustomCredentials::class, $badge); - self::assertFalse($badge->isResolved()); - $badge->executeCustomChecker($user); - self::assertTrue($badge->isResolved()); - } - - public function testAuthenticateFailsOnMissingApiTokenForUser(): void - { - $this->expectException(BadCredentialsException::class); - $this->expectExceptionMessage('The user has no activated API account.'); - - $sut = $this->getSut(); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo2', 'HTTP_X-AUTH-TOKEN' => 'bar']); - $passport = $sut->authenticate($request); - - $user = new User(); - - /** @var CustomCredentials $badge */ - $badge = $passport->getBadge(CustomCredentials::class); - $badge->executeCustomChecker($user); - } - - public function testAuthenticateFailsOnWrongPassword(): void - { - $this->expectException(BadCredentialsException::class); - $this->expectExceptionMessage('The presented password is invalid.'); - - $sut = $this->getSut(false); - - $request = new Request([], [], [], [], [], ['REQUEST_URI' => '/api/fooo', 'HTTP_X-AUTH-USER' => 'foo2', 'HTTP_X-AUTH-TOKEN' => 'bar']); - $passport = $sut->authenticate($request); - - $user = new User(); - $user->setApiToken('bar'); - - /** @var CustomCredentials $badge */ - $badge = $passport->getBadge(CustomCredentials::class); - $badge->executeCustomChecker($user); - } -} diff --git a/tests/API/AuthenticationTest.php b/tests/API/AuthenticationTest.php deleted file mode 100644 index 485884501..000000000 --- a/tests/API/AuthenticationTest.php +++ /dev/null @@ -1,92 +0,0 @@ -assertUrlIsSecured('/api/ping'); - } - - public function testPingWithAccessToken(): void - { - $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); - $this->assertAccessIsGranted($client, '/api/ping'); - $response = $client->getResponse()->getContent(); - self::assertIsString($response); - $result = json_decode($response, true); - - self::assertIsArray($result); - self::assertEquals(['message' => 'pong'], $result); - } - - public function testPingWithAuthTokenAndUsername(): void - { - $client = self::createClient([], $this->getAuthHeader(UserFixtures::USERNAME_USER, UserFixtures::DEFAULT_API_TOKEN)); - - $this->assertAccessIsGranted($client, '/api/ping'); - $response = $client->getResponse()->getContent(); - self::assertIsString($response); - $result = json_decode($response, true); - - self::assertIsArray($result); - self::assertEquals(['message' => 'pong'], $result); - } - - public function testPingWithInvalidAuthTokenAndUsername(): void - { - $client = self::createClient([], $this->getAuthHeader(UserFixtures::USERNAME_USER, 'xxxx')); - $url = '/api/ping'; - $method = 'GET'; - - $this->request($client, $url, $method); - $response = $client->getResponse(); - - $data = [ - 'message' => 'Invalid credentials', - ]; - - self::assertIsString($response->getContent()); - - self::assertEquals( - $data, - json_decode($response->getContent(), true), - \sprintf('The secure URL %s is not protected.', $url) - ); - - self::assertEquals( - Response::HTTP_FORBIDDEN, - $response->getStatusCode(), - \sprintf('The secure URL %s has the wrong status code %s.', $url, $response->getStatusCode()) - ); - } - - /** - * @return array - */ - private function getAuthHeader(string $username, string $password): array - { - return [ - 'HTTP_X_AUTH_USER' => $username, - 'HTTP_X_AUTH_TOKEN' => $password, - ]; - } -} diff --git a/tests/API/CustomerControllerTest.php b/tests/API/CustomerControllerTest.php index e26e4ce82..c8b6f40af 100644 --- a/tests/API/CustomerControllerTest.php +++ b/tests/API/CustomerControllerTest.php @@ -229,7 +229,6 @@ class CustomerControllerTest extends APIControllerBaseTestCase self::assertIsArray($result); self::assertApiResponseTypeStructure('CustomerEntity', $result); - self::assertCount(30, array_keys($result)); self::assertNotEmpty($result['id']); self::assertIsArray($result['teams']); self::assertCount(1, $result['teams']); @@ -262,7 +261,8 @@ class CustomerControllerTest extends APIControllerBaseTestCase self::assertNull($result['homepage']); self::assertEquals('Europe/Berlin', $result['timezone']); self::assertNull($result['buyerReference']); - self::assertEquals('#5319e7', $result['color']); + self::assertNull($result['color']); + self::assertEquals('#5319e7', $result['color-safe']); self::assertTrue($result['visible']); self::assertTrue($result['billable']); } @@ -316,7 +316,7 @@ class CustomerControllerTest extends APIControllerBaseTestCase self::assertApiResponseTypeStructure('CustomerEntity', $result); self::assertNotEmpty($result['id']); self::assertIsArray($result['teams']); - self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => '#03A9F4']], $result['teams']); + self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null, 'color-safe' => '#03A9F4']], $result['teams']); self::assertIsArray($result['metaFields']); self::assertEquals([], $result['metaFields']); self::assertEquals('foo', $result['name']); diff --git a/tests/API/ProjectControllerTest.php b/tests/API/ProjectControllerTest.php index 7b794ca41..819a8a4cc 100644 --- a/tests/API/ProjectControllerTest.php +++ b/tests/API/ProjectControllerTest.php @@ -311,7 +311,6 @@ class ProjectControllerTest extends APIControllerBaseTestCase self::assertIsArray($result); self::assertApiResponseTypeStructure('ProjectEntity', $result); - self::assertCount(19, array_keys($result)); self::assertEquals('first one', $result['parentTitle']); self::assertEquals($project->getId(), $result['id']); self::assertIsArray($result['teams']); @@ -329,7 +328,8 @@ class ProjectControllerTest extends APIControllerBaseTestCase self::assertNull($result['orderNumber']); self::assertNull($result['number']); self::assertNull($result['comment']); - self::assertEquals('#2ECC40', $result['color']); + self::assertNull($result['color']); + self::assertEquals('#2ECC40', $result['color-safe']); self::assertTrue($result['globalActivities']); self::assertTrue($result['billable']); self::assertTrue($result['visible']); @@ -374,7 +374,7 @@ class ProjectControllerTest extends APIControllerBaseTestCase self::assertEquals('Test', $result['parentTitle']); self::assertNotEmpty($result['id']); self::assertIsArray($result['teams']); - self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => '#03A9F4']], $result['teams']); + self::assertEquals([['id' => 1, 'name' => 'Test team', 'color' => null, 'color-safe' => '#03A9F4']], $result['teams']); self::assertIsArray($result['metaFields']); self::assertEquals([], $result['metaFields']); self::assertEquals('foo', $result['name']); diff --git a/tests/API/TimesheetControllerTest.php b/tests/API/TimesheetControllerTest.php index d81eb3fb8..97e277a9f 100644 --- a/tests/API/TimesheetControllerTest.php +++ b/tests/API/TimesheetControllerTest.php @@ -28,9 +28,9 @@ use Symfony\Component\HttpFoundation\Response; #[Group('integration')] class TimesheetControllerTest extends APIControllerBaseTestCase { - public const DATE_FORMAT = 'Y-m-d H:i:s'; - public const DATE_FORMAT_HTML5 = 'Y-m-d\TH:i:s'; - public const TEST_TIMEZONE = 'Europe/London'; + public const string DATE_FORMAT = 'Y-m-d H:i:s'; + public const string DATE_FORMAT_HTML5 = 'Y-m-d\TH:i:s'; + public const string TEST_TIMEZONE = 'Europe/London'; /** * @return Timesheet[] @@ -470,8 +470,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'), + 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d H:i:0'), 'description' => 'foo', 'fixedRate' => 2016, 'hourlyRate' => 127, @@ -501,8 +501,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'), + 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d H:i:0'), 'description' => 'foo', 'fixedRate' => 2016, 'hourlyRate' => 127, @@ -538,8 +538,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase 'activity' => 1, 'project' => 1, 'user' => $user->getId(), - 'begin' => ($dateTime->createDateTime('- 8 hours'))->format('Y-m-d H:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'), + 'begin' => ($dateTime->createDateTime('- 8 hours'))->format('Y-m-d H:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d H:i:0'), 'description' => 'foo', ]; $json = json_encode($data); @@ -585,8 +585,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => $activity->getId(), 'project' => $project->getId(), - 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'), - 'end' => (new \DateTime())->format('Y-m-d H:m:s'), + 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:i:s'), + 'end' => (new \DateTime())->format('Y-m-d H:i:s'), 'description' => 'foo', ]; $json = json_encode($data); @@ -612,8 +612,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $em->persist($project); $data = [ - 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'), - 'end' => (new \DateTime())->format('Y-m-d H:m:s'), + 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:i:s'), + 'end' => (new \DateTime())->format('Y-m-d H:i:s'), 'project' => $project->getId(), 'activity' => 99, ]; @@ -635,8 +635,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $em->flush(); $data = [ - 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:m:s'), - 'end' => (new \DateTime())->format('Y-m-d H:m:s'), + 'begin' => (new \DateTime('- 8 hours'))->format('Y-m-d H:i:s'), + 'end' => (new \DateTime())->format('Y-m-d H:i:s'), 'project' => 99, 'activity' => $activity->getId(), ]; @@ -788,8 +788,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'), + 'begin' => ($dateTime->createDateTime('-8 hours'))->format('Y-m-d H:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d H:i:0'), 'description' => 'foo', ]; $json = json_encode($data); @@ -812,8 +812,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => ($dateTime->createDateTime('- 7 hours'))->format('Y-m-d\TH:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d\TH:m:0'), + 'begin' => ($dateTime->createDateTime('- 7 hours'))->format('Y-m-d\TH:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d\TH:i:0'), 'description' => 'foo', 'billable' => false, ]; @@ -853,8 +853,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d\TH:m:s'), - 'end' => (new \DateTime())->format('Y-m-d\TH:m:s'), + 'begin' => (new \DateTime('- 7 hours'))->format('Y-m-d\TH:i:s'), + 'end' => (new \DateTime())->format('Y-m-d\TH:i:s'), 'description' => 'foo', 'exported' => true, ]; @@ -874,12 +874,14 @@ class TimesheetControllerTest extends APIControllerBaseTestCase { $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $timesheets = $this->importFixtureForUser(User::ROLE_USER); + $begin = new \DateTimeImmutable(); + $end = $begin->modify('-1 day'); $data = [ 'activity' => 10, 'project' => 1, - 'begin' => (new \DateTime())->format('Y-m-d H:m'), - 'end' => (new \DateTime('-1 day'))->format('Y-m-d H:m'), + 'begin' => $begin->format('Y-m-d H:m'), + 'end' => $end->format('Y-m-d H:m'), 'description' => 'foo', ]; $json = json_encode($data); @@ -1034,6 +1036,7 @@ class TimesheetControllerTest extends APIControllerBaseTestCase self::assertIsString($content); $result = json_decode($content, true); + self::assertIsArray($result); self::assertEquals(3, \count($result)); foreach ($result as $timesheet) { self::assertIsArray($timesheet); @@ -1284,7 +1287,9 @@ class TimesheetControllerTest extends APIControllerBaseTestCase self::assertIsArray($result); self::assertApiResponseTypeStructure('TimesheetEntity', $result); self::assertEquals('foo', $result['description']); - self::assertEquals([['name' => 'sdfsdf', 'value' => 'nnnnn'], ['name' => '1234567890', 'value' => '1234567890']], $result['metaFields']); + self::assertIsArray($result['metaFields']); + self::assertEquals(['name' => 'sdfsdf', 'value' => 'nnnnn'], $result['metaFields'][0]); + self::assertEquals(['name' => '1234567890', 'value' => '1234567890'], $result['metaFields'][1]); self::assertEquals(['another', 'testing', 'bar'], $result['tags']); $em = $this->getEntityManager(); @@ -1332,8 +1337,8 @@ class TimesheetControllerTest extends APIControllerBaseTestCase $data = [ 'activity' => 1, 'project' => 1, - 'begin' => ($dateTime->createDateTime('- 8 hours'))->format('Y-m-d H:m:0'), - 'end' => ($dateTime->createDateTime())->format('Y-m-d H:m:0'), + 'begin' => ($dateTime->createDateTime('- 8 hours'))->format('Y-m-d H:i:0'), + 'end' => ($dateTime->createDateTime())->format('Y-m-d H:i:0'), 'description' => 'foo', 'fixedRate' => 2016, 'hourlyRate' => 127 @@ -1488,7 +1493,16 @@ class TimesheetControllerTest extends APIControllerBaseTestCase self::assertIsArray($result); self::assertApiResponseTypeStructure('TimesheetEntity', $result); - self::assertEquals(['name' => 'metatestmock', 'value' => 'another,testing,bar'], $result['metaFields'][0]); + self::assertIsArray($result['metaFields']); + $found = false; + foreach ($result['metaFields'] as $field) { + self::assertIsArray($field); + if ($field['name'] === 'metatestmock') { + self::assertEquals(['name' => 'metatestmock', 'value' => 'another,testing,bar'], $field); + $found = true; + } + } + self::assertTrue($found); $em = $this->getEntityManager(); /** @var Timesheet $timesheet */ diff --git a/tests/API/UserControllerTest.php b/tests/API/UserControllerTest.php index 9d63bcbbb..259899ec6 100644 --- a/tests/API/UserControllerTest.php +++ b/tests/API/UserControllerTest.php @@ -327,7 +327,6 @@ class UserControllerTest extends APIControllerBaseTestCase 'username' => '1', // not existing in form 'email' => '', 'plainPassword' => '123456', // not existing in form - 'plainApiToken' => '123456', // not existing in form 'language' => 'xx', 'timezone' => 'XXX/YYY', 'roles' => [ diff --git a/tests/Audit/VersionedTest.php b/tests/Audit/SensitivePropertyTest.php similarity index 58% rename from tests/Audit/VersionedTest.php rename to tests/Audit/SensitivePropertyTest.php index eea08454b..5bc6849d2 100644 --- a/tests/Audit/VersionedTest.php +++ b/tests/Audit/SensitivePropertyTest.php @@ -9,25 +9,20 @@ namespace App\Tests\Audit; -use App\Audit\Versioned; +use App\Audit\SensitiveProperty; use PHPUnit\Framework\Attributes\CoversClass; use Symfony\Component\Form\Test\TypeTestCase; -#[CoversClass(Versioned::class)] -class VersionedTest extends TypeTestCase +#[CoversClass(SensitiveProperty::class)] +class SensitivePropertyTest extends TypeTestCase { - public function testConstruct(): void + public function testHasCorrectAttribute(): void { - $sut = new Versioned(); - self::assertInstanceOf(Versioned::class, $sut); - } - - public function testHasAttributeAttributeOnLoggable(): void - { - $reflection = new \ReflectionClass(Versioned::class); + $sut = new SensitiveProperty(); + $reflection = new \ReflectionClass($sut); /** @var array<\ReflectionAttribute<\Attribute>> $attributes */ $attributes = array_filter($reflection->getAttributes(), fn ($attr) => $attr->getName() === \Attribute::class); - self::assertCount(1, $attributes, 'Versioned class should have the Attribute attribute'); + self::assertCount(1, $attributes, 'SensitiveProperty class should have the Attribute attribute'); $attribute = $attributes[0]; self::assertEquals(\Attribute::TARGET_PROPERTY, $attribute->getArguments()[0]); } diff --git a/tests/Command/ActivateUserCommandTest.php b/tests/Command/ActivateUserCommandTest.php index 2871fc18b..aad7426c3 100644 --- a/tests/Command/ActivateUserCommandTest.php +++ b/tests/Command/ActivateUserCommandTest.php @@ -32,12 +32,12 @@ class ActivateUserCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var UserService $userService */ $userService = $container->get(UserService::class); - $this->application->add(new ActivateUserCommand($userService)); + $this->application->addCommand(new ActivateUserCommand($userService)); } public function testCommandName(): void @@ -72,7 +72,7 @@ class ActivateUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] User "chris_user" has been activated.', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ diff --git a/tests/Command/BundleInstallerCommandTest.php b/tests/Command/BundleInstallerCommandTest.php index ae991fada..b8bc9f688 100644 --- a/tests/Command/BundleInstallerCommandTest.php +++ b/tests/Command/BundleInstallerCommandTest.php @@ -35,7 +35,7 @@ class BundleInstallerCommandTest extends KernelTestCase $this->application = new Application($kernel); $command = new $className(); self::assertInstanceOf(AbstractBundleInstallerCommand::class, $command); - $this->application->add($command); + $this->application->addCommand($command); return $this->application->find('kimai:bundle:test:install'); } @@ -77,7 +77,7 @@ class BundleInstallerCommandTest extends KernelTestCase { $command = $this->getCommand(InstallerWithAssetsCommand::class); - $this->application->add(new FakeCommand('assets:install', 0, null)); + $this->application->addCommand(new FakeCommand('assets:install', 0, null)); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); @@ -91,7 +91,7 @@ class BundleInstallerCommandTest extends KernelTestCase { $command = $this->getCommand(InstallerWithAssetsCommand::class); - $this->application->add(new FakeCommand('assets:install', 1, null)); + $this->application->addCommand(new FakeCommand('assets:install', 1, null)); $commandTester = new CommandTester($command); $commandTester->execute(['command' => $command->getName()]); diff --git a/tests/Command/ChangePasswordCommandTest.php b/tests/Command/ChangePasswordCommandTest.php index 36a97245a..d62812628 100644 --- a/tests/Command/ChangePasswordCommandTest.php +++ b/tests/Command/ChangePasswordCommandTest.php @@ -35,12 +35,12 @@ class ChangePasswordCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var UserService $userService */ $userService = $container->get(UserService::class); - $this->application->add(new ChangePasswordCommand($userService)); + $this->application->addCommand(new ChangePasswordCommand($userService)); } public function testCommandName(): void diff --git a/tests/Command/CreateUserCommandTest.php b/tests/Command/CreateUserCommandTest.php index 836158f6f..7addad3c6 100644 --- a/tests/Command/CreateUserCommandTest.php +++ b/tests/Command/CreateUserCommandTest.php @@ -31,10 +31,10 @@ class CreateUserCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var UserService $userService */ $userService = $container->get(UserService::class); - $this->application->add(new CreateUserCommand($userService)); + $this->application->addCommand(new CreateUserCommand($userService)); } public function testCreateUserFailsForShortPassword(): void @@ -52,7 +52,7 @@ class CreateUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] Success! Created user: MyTestUser', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ @@ -76,13 +76,19 @@ class CreateUserCommandTest extends KernelTestCase return $commandTester; } - public function testUserWithEmptyFieldsTriggersValidationProblem(): void + public function testUserWithEmptyPasswordTriggersValidationProblem(): void { $commandTester = $this->createUser('xx', '', 'ROLE_USER', ''); $output = $commandTester->getDisplay(); + self::assertStringContainsString('[ERROR] Password must be a non-empty string', $output); + } + + public function testUserWithEmptyFieldsTriggersValidationProblem(): void + { + $commandTester = $this->createUser('xx', '', 'ROLE_USER', '1'); + $output = $commandTester->getDisplay(); self::assertStringContainsString('[ERROR] email: This value should not be blank', $output); - self::assertStringContainsString('[ERROR] plainPassword: This value should not be blank', $output); - self::assertStringContainsString('[ERROR] plainPassword: This value is too short.', $output); + self::assertStringContainsString('[ERROR] plainPassword: This value is too short. It should have 8 characters or', $output); } public function testUserAlreadyExisting(): void diff --git a/tests/Command/DeactivateUserCommandTest.php b/tests/Command/DeactivateUserCommandTest.php index cf6f065a7..a61391dd3 100644 --- a/tests/Command/DeactivateUserCommandTest.php +++ b/tests/Command/DeactivateUserCommandTest.php @@ -32,11 +32,11 @@ class DeactivateUserCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var UserService $userService */ $userService = $container->get(UserService::class); - $this->application->add(new DeactivateUserCommand($userService)); + $this->application->addCommand(new DeactivateUserCommand($userService)); } public function testCommandName(): void @@ -71,7 +71,7 @@ class DeactivateUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] User "john_user" has been deactivated.', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ diff --git a/tests/Command/DemoteUserCommandTest.php b/tests/Command/DemoteUserCommandTest.php index cef7eead5..53dc95dd7 100644 --- a/tests/Command/DemoteUserCommandTest.php +++ b/tests/Command/DemoteUserCommandTest.php @@ -34,12 +34,12 @@ class DemoteUserCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var UserService $userService */ $userService = $container->get(UserService::class); - $this->application->add(new DemoteUserCommand($userService)); + $this->application->addCommand(new DemoteUserCommand($userService)); } public function testCommandName(): void @@ -82,7 +82,7 @@ class DemoteUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] Role "ROLE_TEAMLEAD" has been removed from user "tony_teamlead".', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ @@ -99,7 +99,7 @@ class DemoteUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] Super administrator role has been removed from the user "susan_super".', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ diff --git a/tests/Command/ExportCreateCommandTest.php b/tests/Command/ExportCreateCommandTest.php index ce74ccc24..7d307656a 100644 --- a/tests/Command/ExportCreateCommandTest.php +++ b/tests/Command/ExportCreateCommandTest.php @@ -73,7 +73,7 @@ class ExportCreateCommandTest extends KernelTestCase $application = new Application($kernel); $container = self::getContainer(); - $application->add(new ExportCreateCommand( + $application->addCommand(new ExportCreateCommand( $container->get(ServiceExport::class), // @phpstan-ignore argument.type $container->get(CustomerRepository::class), // @phpstan-ignore argument.type $container->get(ProjectRepository::class), // @phpstan-ignore argument.type diff --git a/tests/Command/InstallCommandTest.php b/tests/Command/InstallCommandTest.php index 47e8dd27d..60beda96f 100644 --- a/tests/Command/InstallCommandTest.php +++ b/tests/Command/InstallCommandTest.php @@ -27,11 +27,11 @@ class InstallCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); - $this->application->add(new InstallCommand( + $this->application->addCommand(new InstallCommand( $doctrine->getConnection() // @phpstan-ignore argument.type )); } diff --git a/tests/Command/InvoiceCreateCommandTest.php b/tests/Command/InvoiceCreateCommandTest.php index d05e2c9ee..a4e6434d4 100644 --- a/tests/Command/InvoiceCreateCommandTest.php +++ b/tests/Command/InvoiceCreateCommandTest.php @@ -66,7 +66,7 @@ class InvoiceCreateCommandTest extends KernelTestCase $this->application = new Application($kernel); $container = self::getContainer(); - $this->application->add(new InvoiceCreateCommand( + $this->application->addCommand(new InvoiceCreateCommand( $container->get(ServiceInvoice::class), // @phpstan-ignore argument.type $container->get(CustomerRepository::class), // @phpstan-ignore argument.type $container->get(ProjectRepository::class), // @phpstan-ignore argument.type diff --git a/tests/Command/ListUserCommandTest.php b/tests/Command/ListUserCommandTest.php index 02ad59f3a..e789418ac 100644 --- a/tests/Command/ListUserCommandTest.php +++ b/tests/Command/ListUserCommandTest.php @@ -36,7 +36,7 @@ class ListUserCommandTest extends KernelTestCase $kernel = self::bootKernel(); $application = new Application($kernel); - $application->add(new ListUserCommand($repository)); + $application->addCommand(new ListUserCommand($repository)); $command = $application->find('kimai:user:list'); $commandTester = new CommandTester($command); diff --git a/tests/Command/MailTestCommandTest.php b/tests/Command/MailTestCommandTest.php index 1b425afbd..1b0feccc7 100644 --- a/tests/Command/MailTestCommandTest.php +++ b/tests/Command/MailTestCommandTest.php @@ -27,7 +27,7 @@ class MailTestCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $this->application->add(new MailTestCommand( + $this->application->addCommand(new MailTestCommand( $this->createMock(EventDispatcherInterface::class) )); } diff --git a/tests/Command/PluginCommandTest.php b/tests/Command/PluginCommandTest.php index b76ddd912..229ca03d2 100644 --- a/tests/Command/PluginCommandTest.php +++ b/tests/Command/PluginCommandTest.php @@ -43,7 +43,7 @@ class PluginCommandTest extends KernelTestCase $projectDirectory = __DIR__ . '/../../'; $kernel = self::bootKernel(); $this->application = new Application($kernel); - $this->application->add(new PluginCommand(new PluginManager($plugins), new PackageManager($projectDirectory), $projectDirectory)); + $this->application->addCommand(new PluginCommand(new PluginManager($plugins), new PackageManager($projectDirectory), $projectDirectory)); $command = $this->application->find('kimai:plugins'); $commandTester = new CommandTester($command); diff --git a/tests/Command/PromoteUserCommandTest.php b/tests/Command/PromoteUserCommandTest.php index 3a8429164..8bc57569b 100644 --- a/tests/Command/PromoteUserCommandTest.php +++ b/tests/Command/PromoteUserCommandTest.php @@ -34,12 +34,12 @@ class PromoteUserCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); $userService = $container->get(UserService::class); self::assertInstanceOf(UserService::class, $userService); - $this->application->add(new PromoteUserCommand($userService)); + $this->application->addCommand(new PromoteUserCommand($userService)); } public function testCommandName(): void @@ -82,7 +82,7 @@ class PromoteUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] Role "ROLE_TEAMLEAD" has been added to user "john_user".', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ @@ -99,7 +99,7 @@ class PromoteUserCommandTest extends KernelTestCase $output = $commandTester->getDisplay(); self::assertStringContainsString('[OK] User "john_user" has been promoted as a super administrator.', $output); - $container = self::$kernel->getContainer(); + $container = self::getContainer(); /** @var Registry $doctrine */ $doctrine = $container->get('doctrine'); /** @var UserRepository $userRepository */ diff --git a/tests/Command/ReloadCommandTest.php b/tests/Command/ReloadCommandTest.php index 6e75489bf..e6f5f5806 100644 --- a/tests/Command/ReloadCommandTest.php +++ b/tests/Command/ReloadCommandTest.php @@ -26,7 +26,7 @@ class ReloadCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $this->application->add(new ReloadCommand( + $this->application->addCommand(new ReloadCommand( $this->application->getKernel()->getProjectDir(), $this->application->getKernel()->getEnvironment() )); diff --git a/tests/Command/ResetDevelopmentCommandTest.php b/tests/Command/ResetDevelopmentCommandTest.php index eaebd5054..f6956415b 100644 --- a/tests/Command/ResetDevelopmentCommandTest.php +++ b/tests/Command/ResetDevelopmentCommandTest.php @@ -23,7 +23,7 @@ class ResetDevelopmentCommandTest extends KernelTestCase { $kernel = self::bootKernel(); $application = new Application($kernel); - $application->add(new ResetDevelopmentCommand('dev', __DIR__ . '/../../')); + $application->addCommand(new ResetDevelopmentCommand('dev', __DIR__ . '/../../')); self::assertTrue($application->has('kimai:reset:dev')); $command = $application->find('kimai:reset:dev'); diff --git a/tests/Command/ResetTestCommandTest.php b/tests/Command/ResetTestCommandTest.php index cc20d1cb0..b632e1afc 100644 --- a/tests/Command/ResetTestCommandTest.php +++ b/tests/Command/ResetTestCommandTest.php @@ -25,7 +25,7 @@ class ResetTestCommandTest extends KernelTestCase { $kernel = self::bootKernel(); $application = new Application($kernel); - $application->add(new ResetTestCommand( + $application->addCommand(new ResetTestCommand( $this->createMock(EntityManagerInterface::class), $this->createMock(UserPasswordHasherInterface::class), 'test' diff --git a/tests/Command/TimesheetStopAllCommandTest.php b/tests/Command/TimesheetStopAllCommandTest.php index 5337b19dd..764bb4b23 100644 --- a/tests/Command/TimesheetStopAllCommandTest.php +++ b/tests/Command/TimesheetStopAllCommandTest.php @@ -31,7 +31,7 @@ class TimesheetStopAllCommandTest extends KernelTestCase parent::setUp(); $kernel = self::bootKernel(); $this->application = new Application($kernel); - $this->application->add(new TimesheetStopAllCommand($service)); + $this->application->addCommand(new TimesheetStopAllCommand($service)); } public function testCommandName(): void diff --git a/tests/Command/UserLoginLinkCommandTest.php b/tests/Command/UserLoginLinkCommandTest.php index a90eb427e..d67d80302 100644 --- a/tests/Command/UserLoginLinkCommandTest.php +++ b/tests/Command/UserLoginLinkCommandTest.php @@ -34,7 +34,7 @@ class UserLoginLinkCommandTest extends KernelTestCase $userRepository = $this->createMock(UserRepository::class); $requestStack = $this->createMock(RequestStack::class); - $this->application->add(new UserLoginLinkCommand($loginLinkHandler, $userRepository, $requestStack)); + $this->application->addCommand(new UserLoginLinkCommand($loginLinkHandler, $userRepository, $requestStack)); } public function testCommandName(): void diff --git a/tests/Command/VersionCommandTest.php b/tests/Command/VersionCommandTest.php index 4805bd58d..0dcca5f63 100644 --- a/tests/Command/VersionCommandTest.php +++ b/tests/Command/VersionCommandTest.php @@ -30,7 +30,7 @@ class VersionCommandTest extends KernelTestCase $kernel = self::bootKernel(); $this->application = new Application($kernel); - $this->application->add(new VersionCommand()); + $this->application->addCommand(new VersionCommand()); } #[DataProvider('getTestData')] diff --git a/tests/Controller/AbstractControllerBaseTestCase.php b/tests/Controller/AbstractControllerBaseTestCase.php index 2baa095f5..1c3e9f499 100644 --- a/tests/Controller/AbstractControllerBaseTestCase.php +++ b/tests/Controller/AbstractControllerBaseTestCase.php @@ -272,6 +272,12 @@ abstract class AbstractControllerBaseTestCase extends WebTestCase self::assertEquals($count, $node->count()); } + protected function assertDataTableRowCountGreaterThan(HttpKernelBrowser $client, string $class, int $count): void + { + $node = $client->getCrawler()->filter('section.content div.' . $class . ' table.dataTable tbody tr:not(.summary)'); + self::assertGreaterThanOrEqual($count, $node->count()); + } + /** * @param array $buttons */ @@ -279,15 +285,21 @@ abstract class AbstractControllerBaseTestCase extends WebTestCase { $node = $client->getCrawler()->filter('div.page-header div.page-actions .pa-desktop a'); + /** @var array $foundButtons */ + $foundButtons = []; + /** @var \DOMElement $element */ foreach ($node->getIterator() as $element) { $expectedClass = trim(str_replace(['btn action-', ' btn-icon', 'btn btn-primary action-', 'btn btn-dark action-', 'btn btn-white action-', 'btn action-'], '', $element->getAttribute('class'))); - self::assertArrayHasKey($expectedClass, $buttons); - $expectedUrl = $buttons[$expectedClass]; - self::assertEquals($expectedUrl, $element->getAttribute('href')); + $foundButtons[$expectedClass] = $element->getAttribute('href'); } - self::assertEquals(\count($buttons), $node->count(), 'Invalid amount of page actions'); + foreach ($buttons as $class => $url) { + self::assertArrayHasKey($class, $foundButtons); + self::assertEquals($foundButtons[$class], $url); + } + + self::assertGreaterThanOrEqual(\count($buttons), $node->count(), 'Invalid amount of page actions'); } /** diff --git a/tests/Controller/ContractControllerTest.php b/tests/Controller/ContractControllerTest.php index 172272730..ae2f61e26 100644 --- a/tests/Controller/ContractControllerTest.php +++ b/tests/Controller/ContractControllerTest.php @@ -39,8 +39,8 @@ class ContractControllerTest extends AbstractControllerBaseTestCase { $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); - /** @var UserRepository $repository */ - $repository = $this->getPrivateService(UserRepository::class); + /** @var UserRepository $userRepository */ + $userRepository = $this->getPrivateService(UserRepository::class); $user = $this->loadUserFromDatabase(UserFixtures::USERNAME_USER); $user->setWorkContractMode(WorkingTimeModeDay::ID); $user->setPreferenceValue(WorkingTimeCalculatorDay::WORK_HOURS_MONDAY, '28800'); @@ -50,7 +50,7 @@ class ContractControllerTest extends AbstractControllerBaseTestCase $user->setPreferenceValue(WorkingTimeCalculatorDay::WORK_HOURS_FRIDAY, '19800'); $user->setPreferenceValue(WorkingTimeCalculatorDay::WORK_HOURS_SATURDAY, '0'); $user->setPreferenceValue(WorkingTimeCalculatorDay::WORK_HOURS_SUNDAY, '0'); - $repository->saveUser($user); + $userRepository->saveUser($user); $this->assertAccessIsGranted($client, '/contract'); $content = $client->getResponse()->getContent(); diff --git a/tests/Controller/HelpControllerTest.php b/tests/Controller/HelpControllerTest.php index 022ed1e68..208409366 100644 --- a/tests/Controller/HelpControllerTest.php +++ b/tests/Controller/HelpControllerTest.php @@ -19,6 +19,6 @@ class HelpControllerTest extends AbstractControllerBaseTestCase { $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $this->assertAccessIsGranted($client, '/help/locales'); - $this->assertDataTableRowCount($client, 'datatable_help_locales', 25); // @see services_test.yaml + $this->assertDataTableRowCount($client, 'datatable_help_locales', 290); } } diff --git a/tests/Controller/InvoiceControllerTest.php b/tests/Controller/InvoiceControllerTest.php index 8c601a6aa..1095e939b 100644 --- a/tests/Controller/InvoiceControllerTest.php +++ b/tests/Controller/InvoiceControllerTest.php @@ -35,16 +35,12 @@ class InvoiceControllerTest extends AbstractControllerBaseTestCase private function clearInvoiceFiles(): void { - $path = __DIR__ . '/../_data/invoices/'; - - if (is_dir($path)) { - $files = glob($path . '*'); - if ($files === false) { - return; - } - foreach ($files as $file) { - unlink($file); - } + $files = glob(__DIR__ . '/../_data/invoices*/*'); + if ($files === false) { + return; + } + foreach ($files as $file) { + unlink($file); } } diff --git a/tests/Controller/PermissionControllerTest.php b/tests/Controller/PermissionControllerTest.php index 605422ab0..99e29e7fa 100644 --- a/tests/Controller/PermissionControllerTest.php +++ b/tests/Controller/PermissionControllerTest.php @@ -33,7 +33,7 @@ class PermissionControllerTest extends AbstractControllerBaseTestCase $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->assertAccessIsGranted($client, '/admin/permissions'); $this->assertHasDataTable($client); - $this->assertDataTableRowCount($client, 'datatable_user_admin_permissions', 136); + $this->assertDataTableRowCountGreaterThan($client, 'datatable_user_admin_permissions', 136); $this->assertPageActions($client, [ 'create modal-ajax-form' => $this->createUrl('/admin/permissions/roles/create'), ]); diff --git a/tests/Controller/PluginControllerTest.php b/tests/Controller/PluginControllerTest.php index 9bed51baf..7cf893a2b 100644 --- a/tests/Controller/PluginControllerTest.php +++ b/tests/Controller/PluginControllerTest.php @@ -30,6 +30,10 @@ class PluginControllerTest extends AbstractControllerBaseTestCase public function testIndexAction(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); + + $manager = new PluginManager([]); + self::getContainer()->set(PluginManager::class, $manager); + $this->assertAccessIsGranted($client, '/admin/plugins/'); $node = $client->getCrawler()->filter('div.alert.alert-warning'); self::assertStringContainsString('You have no plugins installed yet', $node->text(null, true)); diff --git a/tests/Controller/ProfileControllerTest.php b/tests/Controller/ProfileControllerTest.php index 69e6f9e37..f0a8545a1 100644 --- a/tests/Controller/ProfileControllerTest.php +++ b/tests/Controller/ProfileControllerTest.php @@ -242,7 +242,7 @@ class ProfileControllerTest extends AbstractControllerBaseTestCase ); } - public function testCreateApiToken(): void + public function testCreateAccessToken(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); @@ -283,61 +283,6 @@ class ProfileControllerTest extends AbstractControllerBaseTestCase self::assertEquals($code->innerText(), $tokens[1]->getToken()); } - #[Group('legacy')] - public function testCreateApiPassword(): void - { - $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); - $this->request($client, '/profile/' . UserFixtures::USERNAME_USER . '/api-token'); - - $user = $this->getUserByRole(User::ROLE_USER); - /** @var PasswordHasherFactoryInterface $passwordEncoder */ - $passwordEncoder = self::getContainer()->get('security.password_hasher_factory'); - - self::assertTrue($passwordEncoder->getPasswordHasher($user)->verify($user->getApiToken(), UserFixtures::DEFAULT_API_TOKEN)); - self::assertFalse($passwordEncoder->getPasswordHasher($user)->verify($user->getApiToken(), 'test1234')); - self::assertEquals(UserFixtures::USERNAME_USER, $user->getUserIdentifier()); - - $form = $client->getCrawler()->filter('form[name=user_api_password]')->form(); - $client->submit($form, [ - 'user_api_password' => [ - 'plainApiToken' => [ - 'first' => 'test1234', - 'second' => 'test1234', - ] - ] - ]); - - $this->assertIsRedirect($client, $this->createUrl('/profile/' . urlencode(UserFixtures::USERNAME_USER) . '/api-token')); - $client->followRedirect(); - self::assertTrue($client->getResponse()->isSuccessful()); - - $this->assertHasFlashSuccess($client); - - $user = $this->getUserByRole(User::ROLE_USER); - - self::assertFalse($passwordEncoder->getPasswordHasher($user)->verify($user->getApiToken(), UserFixtures::DEFAULT_API_TOKEN)); - self::assertTrue($passwordEncoder->getPasswordHasher($user)->verify($user->getApiToken(), 'test1234')); - } - - #[Group('legacy')] - public function testCreateApiPasswordFailsIfPasswordLengthToShort(): void - { - $this->assertFormHasValidationError( - User::ROLE_USER, - '/profile/' . UserFixtures::USERNAME_USER . '/api-token', - 'form[name=user_api_password]', - [ - 'user_api_password' => [ - 'plainApiToken' => [ - 'first' => 'abcdef1', - 'second' => 'abcdef1', - ] - ] - ], - ['#user_api_password_plainApiToken_first'] - ); - } - public function testRolesActionIsSecured(): void { $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); @@ -602,13 +547,13 @@ class ProfileControllerTest extends AbstractControllerBaseTestCase $form = $client->getCrawler()->filter('form[name=user_contract]')->form(); $client->submit($form, [ - 'user_contract[workHoursMonday]' => '1:00', - 'user_contract[workHoursTuesday]' => '2:00', - 'user_contract[workHoursWednesday]' => '3:00', - 'user_contract[workHoursThursday]' => '4:30', - 'user_contract[workHoursFriday]' => '5:12', - 'user_contract[workHoursSaturday]' => '6:59', - 'user_contract[workHoursSunday]' => '0:01', + 'user_contract[work_monday]' => '1:00', + 'user_contract[work_tuesday]' => '2:00', + 'user_contract[work_wednesday]' => '3:00', + 'user_contract[work_thursday]' => '4:30', + 'user_contract[work_friday]' => '5:12', + 'user_contract[work_saturday]' => '6:59', + 'user_contract[work_sunday]' => '0:01', ]); $this->assertIsRedirect($client, $this->createUrl('/profile/' . urlencode(UserFixtures::USERNAME_USER) . '/contract')); diff --git a/tests/Controller/ProjectControllerTest.php b/tests/Controller/ProjectControllerTest.php index 8b27535ce..87578c37f 100644 --- a/tests/Controller/ProjectControllerTest.php +++ b/tests/Controller/ProjectControllerTest.php @@ -236,6 +236,7 @@ class ProjectControllerTest extends AbstractControllerBaseTestCase /** @var EntityManager $em */ $em = $this->getEntityManager(); $project = $em->find(Project::class, 1); + self::assertInstanceOf(Project::class, $project); $project->setMetaField((new ProjectMeta())->setName('foo')->setValue('bar')); $project->setEnd(new \DateTime()); $em->persist($project); @@ -276,6 +277,7 @@ class ProjectControllerTest extends AbstractControllerBaseTestCase /** @var EntityManager $em */ $em = $this->getEntityManager(); $project = $em->find(Project::class, 1); + self::assertInstanceOf(Project::class, $project); $project->setMetaField((new ProjectMeta())->setName('foo')->setValue('bar')); $project->setEnd(new \DateTime()); $em->persist($project); diff --git a/tests/Controller/ReportingControllerTest.php b/tests/Controller/ReportingControllerTest.php index b01ef34cf..6ea7880cf 100644 --- a/tests/Controller/ReportingControllerTest.php +++ b/tests/Controller/ReportingControllerTest.php @@ -25,7 +25,7 @@ class ReportingControllerTest extends AbstractControllerBaseTestCase $client = $this->getClientForAuthenticatedUser(User::ROLE_ADMIN); $this->request($client, '/reporting/'); $nodes = $client->getCrawler()->filter('section.content div.row-cards a.card-link'); - self::assertCount(11, $nodes); + self::assertGreaterThanOrEqual(11, $nodes->count()); } public function testAllReports(): void @@ -33,7 +33,7 @@ class ReportingControllerTest extends AbstractControllerBaseTestCase $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); $this->request($client, '/reporting/'); $nodes = $client->getCrawler()->filter('section.content div.row-cards a.card-link'); - self::assertCount(11, $nodes); + self::assertGreaterThanOrEqual(11, $nodes->count()); foreach ($nodes as $node) { self::assertNotNull($node->attributes); $link = $node->attributes->getNamedItem('href'); @@ -41,8 +41,9 @@ class ReportingControllerTest extends AbstractControllerBaseTestCase $url = $link->nodeValue; self::assertNotNull($url); self::assertNotEmpty($url); - self::assertStringStartsWith('/en/reporting/', $url); - $this->request($client, $url); + if (str_starts_with($url, '/en/reporting/')) { + $this->request($client, $url); + } } } @@ -51,6 +52,6 @@ class ReportingControllerTest extends AbstractControllerBaseTestCase $client = $this->getClientForAuthenticatedUser(User::ROLE_USER); $this->request($client, '/reporting/'); $nodes = $client->getCrawler()->filter('section.content div.row-cards a.card-link'); - self::assertCount(3, $nodes); + self::assertGreaterThanOrEqual(3, $nodes->count()); } } diff --git a/tests/Controller/SystemConfigurationControllerTest.php b/tests/Controller/SystemConfigurationControllerTest.php index d29e0608a..08e747971 100644 --- a/tests/Controller/SystemConfigurationControllerTest.php +++ b/tests/Controller/SystemConfigurationControllerTest.php @@ -40,10 +40,10 @@ class SystemConfigurationControllerTest extends AbstractControllerBaseTestCase $expectedCount = \count($expectedForms) + 1; // the menu is another card $result = $client->getCrawler()->filter('section.content div.card'); - self::assertEquals($expectedCount, \count($result)); + self::assertGreaterThanOrEqual($expectedCount, \count($result)); $result = $client->getCrawler()->filter('section.content div.card form'); - self::assertEquals(\count($expectedForms), \count($result)); + self::assertGreaterThanOrEqual(\count($expectedForms), \count($result)); foreach ($expectedForms as $formConfig) { $result = $client->getCrawler()->filter($formConfig[0]); diff --git a/tests/Customer/CustomerServiceTest.php b/tests/Customer/CustomerServiceTest.php index 619ddb61a..fc4f7f367 100644 --- a/tests/Customer/CustomerServiceTest.php +++ b/tests/Customer/CustomerServiceTest.php @@ -169,7 +169,7 @@ class CustomerServiceTest extends TestCase */ public static function getTestData(): array { - $dateTime = new \DateTime(); + $dateTime = new \DateTime('now', new \DateTimeZone('Europe/Vienna')); $yearLong = (int) $dateTime->format('Y'); $yearShort = (int) $dateTime->format('y'); diff --git a/tests/DataFixtures/InvoiceTemplateFixtures.php b/tests/DataFixtures/InvoiceTemplateFixtures.php index bb768218d..ddb3dd171 100644 --- a/tests/DataFixtures/InvoiceTemplateFixtures.php +++ b/tests/DataFixtures/InvoiceTemplateFixtures.php @@ -43,7 +43,7 @@ class InvoiceTemplateFixtures implements TestFixture $template->setName('Invoice'); $template->setTitle('Your company name'); $template->setCustomer($customer); - $template->setVat(19); + $template->setTaxRate(19.0); $template->setDueDays(14); $template->setPaymentTerms( 'I would like to thank you for your confidence and will gladly be there for you in the future.' . diff --git a/tests/DependencyInjection/AppExtensionTest.php b/tests/DependencyInjection/AppExtensionTest.php index 84f1226b7..f72faf652 100644 --- a/tests/DependencyInjection/AppExtensionTest.php +++ b/tests/DependencyInjection/AppExtensionTest.php @@ -69,31 +69,26 @@ class AppExtensionTest extends TestCase 'en' => [ 'date' => 'M/d/y', 'time' => 'h:mm a', - 'rtl' => false, 'translation' => true, ], 'de' => [ 'date' => 'dd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'he' => [ 'date' => 'd.M.y', 'time' => 'HH:mm', - 'rtl' => true, 'translation' => true, ], 'tr' => [ 'date' => 'd.MM.y', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], 'zh_CN' => [ 'date' => 'y/M/d', 'time' => 'HH:mm', - 'rtl' => false, 'translation' => true, ], ], diff --git a/tests/Entity/AbstractEntityTestCase.php b/tests/Entity/AbstractEntityTestCase.php index 04e5e45ed..f41f49ca9 100644 --- a/tests/Entity/AbstractEntityTestCase.php +++ b/tests/Entity/AbstractEntityTestCase.php @@ -58,7 +58,6 @@ abstract class AbstractEntityTestCase extends TestCase self::assertNull($sut->getId()); $obj = new \ReflectionObject($sut); $prop = $obj->getProperty('id'); - $prop->setAccessible(true); $prop->setValue($sut, 123); self::assertEquals(123, $sut->getId()); @@ -66,6 +65,5 @@ abstract class AbstractEntityTestCase extends TestCase self::assertNull($clone->getId()); $prop->setValue($sut, null); - $prop->setAccessible(false); } } diff --git a/tests/Entity/AbstractMetaEntityTestCase.php b/tests/Entity/AbstractMetaEntityTestCase.php index 42d2a6c27..0ff627a64 100644 --- a/tests/Entity/AbstractMetaEntityTestCase.php +++ b/tests/Entity/AbstractMetaEntityTestCase.php @@ -70,12 +70,12 @@ abstract class AbstractMetaEntityTestCase extends TestCase self::assertInstanceOf(MetaTableTypeInterface::class, $sut->setOrder(7)); self::assertEquals(7, $sut->getOrder()); - self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new Length(['max' => 10]))); - self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new NotNull([]))); - self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new NotBlank([]))); + self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new Length(max: 10))); + self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new NotNull())); + self::assertInstanceOf(MetaTableTypeInterface::class, $sut->addConstraint(new NotBlank())); self::assertCount(3, $sut->getConstraints()); - self::assertInstanceOf(MetaTableTypeInterface::class, $sut->setConstraints([new Length(['min' => 2])])); + self::assertInstanceOf(MetaTableTypeInterface::class, $sut->setConstraints([new Length(min: 2)])); self::assertCount(1, $sut->getConstraints()); self::assertInstanceOf(MetaTableTypeInterface::class, $sut->setOptions(['foo' => 'bar'])); @@ -125,7 +125,7 @@ abstract class AbstractMetaEntityTestCase extends TestCase $meta2->setIsRequired(true); $meta2->setIsVisible(true); $meta2->setOrder(93); - $meta2->setConstraints([new NotBlank(), new Length(['min' => 1])]); + $meta2->setConstraints([new NotBlank(), new Length(min: 1)]); $meta2->setOptions(['foo1' => 'bar1']); self::assertInstanceOf(MetaTableTypeInterface::class, $meta1->merge($meta2)); diff --git a/tests/Entity/ExportTemplateTest.php b/tests/Entity/ExportTemplateTest.php index 39229a81b..a2fecc53b 100644 --- a/tests/Entity/ExportTemplateTest.php +++ b/tests/Entity/ExportTemplateTest.php @@ -113,7 +113,6 @@ class ExportTemplateTest extends AbstractEntityTestCase $sut = new ExportTemplate(); $r = new \ReflectionObject($sut); $p = $r->getProperty('id'); - $p->setAccessible(true); $p->setValue($sut, 13); self::assertEquals(13, $sut->getId()); self::assertFalse($sut->isNew()); diff --git a/tests/Entity/InvoiceTemplateTest.php b/tests/Entity/InvoiceTemplateTest.php index dc3a55df2..bbaa1fa54 100644 --- a/tests/Entity/InvoiceTemplateTest.php +++ b/tests/Entity/InvoiceTemplateTest.php @@ -13,8 +13,8 @@ use App\Entity\Customer; use App\Entity\CustomerMeta; use App\Entity\InvoiceTemplate; use App\Entity\InvoiceTemplateMeta; -use App\Entity\Tax; use App\Entity\TaxType; +use App\Invoice\Tax; use Doctrine\Common\Collections\Collection; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -40,7 +40,7 @@ class InvoiceTemplateTest extends TestCase self::assertEquals('default', $sut->getNumberGenerator()); self::assertEquals('default', $sut->getRenderer()); self::assertEquals(30, $sut->getDueDays()); - self::assertTrue($sut->isDecimalDuration()); // @phpstan-ignore method.deprecated + self::assertTrue($sut->isDecimalDuration()); self::assertInstanceOf(Collection::class, $sut->getMetaFields()); self::assertEquals(0, $sut->getMetaFields()->count()); self::assertNull($sut->getMetaField('foo')); @@ -101,11 +101,13 @@ class InvoiceTemplateTest extends TestCase $sut->setContact('hello world'); self::assertEquals('hello world', $sut->getContact()); - $sut->setVat(7.31); - self::assertEquals(7.31, $sut->getVat()); + $sut->setTaxRate(17.31); + self::assertEquals(17.31, $sut->getTaxRate()); + self::assertEquals(17.31, $sut->getVat()); - $sut->setVatId('1234567890'); // @phpstan-ignore method.deprecated - self::assertEquals('1234567890', $sut->getVatId()); + $sut->setVat(7.31); + self::assertEquals(7.31, $sut->getTaxRate()); + self::assertEquals(7.31, $sut->getVat()); $sut->setLanguage('de'); self::assertEquals('de', $sut->getLanguage()); @@ -119,11 +121,9 @@ class InvoiceTemplateTest extends TestCase $sut->setCalculator('fooBar'); self::assertEquals('fooBar', $sut->getCalculator()); - $sut->setCompany('looney toon'); // @phpstan-ignore method.deprecated - self::assertEquals('looney toon', $sut->getCompany()); - - $sut->setAddress('acme street, 1234 looney town, rainbow'); // @phpstan-ignore method.deprecated - self::assertEquals('acme street, 1234 looney town, rainbow', $sut->getAddress()); + self::assertNull($sut->getVatId()); + self::assertNull($sut->getCompany()); + self::assertNull($sut->getAddress()); self::assertEquals($sut, clone $sut); diff --git a/tests/Entity/InvoiceTest.php b/tests/Entity/InvoiceTest.php index 98ce8d170..d4151d2b5 100644 --- a/tests/Entity/InvoiceTest.php +++ b/tests/Entity/InvoiceTest.php @@ -151,7 +151,8 @@ class InvoiceTest extends AbstractEntityTestCase $template = new InvoiceTemplate(); $template->setTitle('a test invoice template title'); - $template->setVat(19); + $template->setTaxRate(19.0); + $template->setTaxRate(19); $template->setDueDays(9); $project = new Project(); diff --git a/tests/Entity/TeamTest.php b/tests/Entity/TeamTest.php index 55e3a7f15..60d934b98 100644 --- a/tests/Entity/TeamTest.php +++ b/tests/Entity/TeamTest.php @@ -267,9 +267,7 @@ class TeamTest extends TestCase $reflection = new \ReflectionClass($team); $property = $reflection->getProperty('id'); - $property->setAccessible(true); $property->setValue($team, 99); - $property->setAccessible(false); self::assertEquals(99, $team->getId()); $sut = clone $team; diff --git a/tests/Entity/TimesheetTest.php b/tests/Entity/TimesheetTest.php index 18102f52b..cbd3691d8 100644 --- a/tests/Entity/TimesheetTest.php +++ b/tests/Entity/TimesheetTest.php @@ -166,9 +166,7 @@ class TimesheetTest extends TestCase $reflection = new \ReflectionClass($sut); $property = $reflection->getProperty('modifiedAt'); - $property->setAccessible(true); $property->setValue($sut, $modifiedDate); - $property->setAccessible(false); self::assertEquals($modifiedDate, $sut->getModifiedAt()); diff --git a/tests/Entity/TimesheetValidationTest.php b/tests/Entity/TimesheetValidationTest.php index a97b620cf..802347670 100644 --- a/tests/Entity/TimesheetValidationTest.php +++ b/tests/Entity/TimesheetValidationTest.php @@ -70,9 +70,18 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationProjectMismatch(): void { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer); - $project2 = (new Project())->setName('bar')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project); + + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + + $project2 = new Project(); + $project2->setName('bar'); + $project2->setCustomer($customer); + + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = new Timesheet(); $entity->setUser(new User()); @@ -116,9 +125,7 @@ class TimesheetValidationTest extends KernelTestCase if ($id !== null) { $o = new \ReflectionClass($entity); $p = $o->getProperty('id'); - $p->setAccessible(true); $p->setValue($entity, $id); - $p->setAccessible(false); } return $entity; @@ -159,8 +166,15 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationProjectInvisible(): void { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer)->setVisible(false); - $activity = (new Activity())->setName('hello-world')->setProject($project); + + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $project->setVisible(false); + + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = new Timesheet(); $entity->setUser(new User()); @@ -175,8 +189,15 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationProjectInvisibleDoesNotTriggerOnStoppedEntities(): void { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer)->setVisible(false); - $activity = (new Activity())->setName('hello-world')->setProject($project); + + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $project->setVisible(false); + + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = $this->createStoppedTimesheet($project, $activity, 1); @@ -186,8 +207,14 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationProjectInvisibleDoesTriggerOnNewEntities(): void { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer)->setVisible(false); - $activity = (new Activity())->setName('hello-world')->setProject($project); + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + $project->setVisible(false); + + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); $entity = $this->createStoppedTimesheet($project, $activity); @@ -197,8 +224,15 @@ class TimesheetValidationTest extends KernelTestCase public function testValidationActivityInvisible(): void { $customer = new Customer('foo'); - $project = (new Project())->setName('foo')->setCustomer($customer); - $activity = (new Activity())->setName('hello-world')->setProject($project)->setVisible(false); + + $project = new Project(); + $project->setName('foo'); + $project->setCustomer($customer); + + $activity = new Activity(); + $activity->setName('hello-world'); + $activity->setProject($project); + $activity->setVisible(false); $entity = new Timesheet(); $entity->setUser(new User()); diff --git a/tests/Entity/UserTest.php b/tests/Entity/UserTest.php index 2bbd5864b..fc39201eb 100644 --- a/tests/Entity/UserTest.php +++ b/tests/Entity/UserTest.php @@ -20,7 +20,6 @@ use App\Tests\Security\TestUserEntity; use App\WorkingTime\Mode\WorkingTimeModeDay; use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\User\EquatableInterface; use Symfony\Component\Security\Core\User\UserInterface; @@ -40,15 +39,12 @@ class UserTest extends TestCase self::assertNull($user->getAlias()); self::assertNull($user->getId()); self::assertNull($user->getAccountNumber()); - self::assertNull($user->getApiToken()); - self::assertNull($user->getPlainApiToken()); self::assertFalse($user->hasTotpSecret()); self::assertNull($user->getTotpSecret()); self::assertEquals(User::DEFAULT_LANGUAGE, $user->getLanguage()); self::assertEquals(User::DEFAULT_LANGUAGE, $user->getLocale()); self::assertFalse($user->hasTeamAssignment()); self::assertFalse($user->canSeeAllData()); - self::assertFalse($user->isExportDecimal()); self::assertFalse($user->isSystemAccount()); self::assertFalse($user->isPasswordRequestNonExpired(-1)); self::assertFalse($user->isPasswordRequestNonExpired(0)); @@ -65,15 +61,9 @@ class UserTest extends TestCase $user->setAvatar('https://www.gravatar.com/avatar/00000000000000000000000000000000?d=retro&f=y'); self::assertEquals('https://www.gravatar.com/avatar/00000000000000000000000000000000?d=retro&f=y', $user->getAvatar()); - $user->setApiToken('nbvfdswe34567ujko098765rerfghbgvfcdsert'); - self::assertEquals('nbvfdswe34567ujko098765rerfghbgvfcdsert', $user->getApiToken()); - $user->setTotpSecret('ertzuio878t6rtdrjfcghvjkiu87'); self::assertEquals('ertzuio878t6rtdrjfcghvjkiu87', $user->getTotpSecret()); - $user->setPlainApiToken('https://www.gravatar.com/avatar/nbvfdswe34567ujko098765rerfghbgvfcdsert'); - self::assertEquals('https://www.gravatar.com/avatar/nbvfdswe34567ujko098765rerfghbgvfcdsert', $user->getPlainApiToken()); - $user->setTitle('Mr. Code Blaster'); self::assertEquals('Mr. Code Blaster', $user->getTitle()); @@ -87,78 +77,16 @@ class UserTest extends TestCase self::assertNull($user->getSupervisor()); } - /** - * @deprecated - */ - #[Group('legacy')] public function testWorkContract(): void { $user = new User(); - self::assertFalse($user->hasContractSettings()); - - self::assertEquals(0, $user->getWorkHoursMonday()); - self::assertEquals(0, $user->getWorkHoursTuesday()); - self::assertEquals(0, $user->getWorkHoursWednesday()); - self::assertEquals(0, $user->getWorkHoursThursday()); - self::assertEquals(0, $user->getWorkHoursFriday()); - self::assertEquals(0, $user->getWorkHoursSaturday()); - self::assertEquals(0, $user->getWorkHoursSunday()); self::assertFalse($user->hasWorkHourConfiguration()); - $monday = new \DateTime('2023-05-08 12:00:00', new \DateTimeZone('Europe/Berlin')); - $tuesday = new \DateTime('2023-05-09 12:00:00', new \DateTimeZone('Europe/Berlin')); - $wednesday = new \DateTime('2023-05-10 12:00:00', new \DateTimeZone('Europe/Berlin')); - $thursday = new \DateTime('2023-05-11 12:00:00', new \DateTimeZone('Europe/Berlin')); - $friday = new \DateTime('2023-05-12 12:00:00', new \DateTimeZone('Europe/Berlin')); - $saturday = new \DateTime('2023-05-13 12:00:00', new \DateTimeZone('Europe/Berlin')); - $sunday = new \DateTime('2023-05-14 12:00:00', new \DateTimeZone('Europe/Berlin')); - - self::assertFalse($user->isWorkDay($monday)); - self::assertFalse($user->isWorkDay($tuesday)); - self::assertFalse($user->isWorkDay($wednesday)); - self::assertFalse($user->isWorkDay($thursday)); - self::assertFalse($user->isWorkDay($friday)); - self::assertFalse($user->isWorkDay($saturday)); - self::assertFalse($user->isWorkDay($sunday)); - $user->setWorkContractMode(WorkingTimeModeDay::ID); - $user->setWorkHoursMonday(7200); self::assertTrue($user->hasWorkHourConfiguration()); - $user->setWorkHoursTuesday(7300); - $user->setWorkHoursWednesday(7400); - $user->setWorkHoursThursday(7500); - $user->setWorkHoursFriday(7600); - $user->setWorkHoursSaturday(7700); - $user->setWorkHoursSunday(7800); $user->setHolidaysPerYear(10.7); self::assertTrue($user->hasWorkHourConfiguration()); - self::assertTrue($user->hasContractSettings()); - - self::assertEquals(7200, $user->getWorkHoursMonday()); - self::assertEquals(7300, $user->getWorkHoursTuesday()); - self::assertEquals(7400, $user->getWorkHoursWednesday()); - self::assertEquals(7500, $user->getWorkHoursThursday()); - self::assertEquals(7600, $user->getWorkHoursFriday()); - self::assertEquals(7700, $user->getWorkHoursSaturday()); - self::assertEquals(7800, $user->getWorkHoursSunday()); - self::assertEquals(10.5, $user->getHolidaysPerYear()); - - self::assertEquals(7200, $user->getWorkHoursForDay($monday)); - self::assertEquals(7300, $user->getWorkHoursForDay($tuesday)); - self::assertEquals(7400, $user->getWorkHoursForDay($wednesday)); - self::assertEquals(7500, $user->getWorkHoursForDay($thursday)); - self::assertEquals(7600, $user->getWorkHoursForDay($friday)); - self::assertEquals(7700, $user->getWorkHoursForDay($saturday)); - self::assertEquals(7800, $user->getWorkHoursForDay($sunday)); - - self::assertTrue($user->isWorkDay($monday)); - self::assertTrue($user->isWorkDay($tuesday)); - self::assertTrue($user->isWorkDay($wednesday)); - self::assertTrue($user->isWorkDay($thursday)); - self::assertTrue($user->isWorkDay($friday)); - self::assertTrue($user->isWorkDay($saturday)); - self::assertTrue($user->isWorkDay($sunday)); $user->setPublicHolidayGroup('10'); self::assertEquals('10', $user->getPublicHolidayGroup()); @@ -187,7 +115,7 @@ class UserTest extends TestCase self::assertNull($sut->getColor()); self::assertFalse($sut->hasColor()); - $sut->setUsername('foo test 123'); + $sut->setUserIdentifier('foo test 123'); self::assertEquals('#a972c9', $sut->getColorSafe()); $sut->setColor('#000000'); @@ -267,11 +195,8 @@ class UserTest extends TestCase $user->setPreferenceValue('test2', 'I like rain'); self::assertEquals('I like rain', $user->getPreferenceValue('test2')); - $user->setPreferenceValue('export_decimal', true); - self::assertTrue($user->isExportDecimal()); - $prefs = $user->getPreferences(); - self::assertCount(3, $prefs); + self::assertCount(2, $prefs); $preference1 = new UserPreference('_aaaaa', 'bbbbb'); $user->addPreference($preference1); @@ -280,10 +205,10 @@ class UserTest extends TestCase $user->addPreference($preference2); $prefs = $user->getPreferences(); - self::assertCount(5, $prefs); + self::assertCount(4, $prefs); $visiblePrefs = $user->getVisiblePreferences(); - self::assertCount(3, $visiblePrefs); // export_decimal and _aaaaa is skipped + self::assertCount(3, $visiblePrefs); // _aaaaa is skipped self::assertEquals([$user->getPreference('test'), $user->getPreference('test2'), $preference2], $visiblePrefs); self::assertInstanceOf(UserPreference::class, $prefs[0]); @@ -293,7 +218,7 @@ class UserTest extends TestCase self::assertEquals('test2', $prefs[1]->getName()); self::assertInstanceOf(UserPreference::class, $prefs[2]); - self::assertEquals('export_decimal', $prefs[2]->getName()); + self::assertEquals('_aaaaa', $prefs[2]->getName()); $user->setPreferences(new ArrayCollection([])); self::assertCount(0, $user->getPreferences()); @@ -465,7 +390,6 @@ class UserTest extends TestCase $preference = new UserPreference('test', 'foobar'); $property = new \ReflectionProperty(User::class, 'preferences'); - $property->setAccessible(true); $property->setValue($sut, null); // make sure that addPreference will work, even if the internal collection was set to null diff --git a/tests/Entity/WorkingTimeTest.php b/tests/Entity/WorkingTimeTest.php index 50963506a..04e23444f 100644 --- a/tests/Entity/WorkingTimeTest.php +++ b/tests/Entity/WorkingTimeTest.php @@ -20,7 +20,7 @@ class WorkingTimeTest extends TestCase public function testDefaultValues(): void { $user = new User(); - $user->setUsername('bar'); + $user->setUserIdentifier('bar'); $date = new \DateTimeImmutable(); $sut = new WorkingTime($user, $date); @@ -37,7 +37,7 @@ class WorkingTimeTest extends TestCase $approvedAt = new \DateTimeImmutable('2023-01-01 12:00:00', new \DateTimeZone('Europe/Vienna')); $approvedBy = new User(); - $approvedBy->setUsername('foo'); + $approvedBy->setUserIdentifier('foo'); $sut->setApprovedAt($approvedAt); $sut->setApprovedBy($approvedBy); diff --git a/tests/Event/ConfigureMainMenuEventTest.php b/tests/Event/ConfigureMainMenuEventTest.php index d13600a3b..86892b8bc 100644 --- a/tests/Event/ConfigureMainMenuEventTest.php +++ b/tests/Event/ConfigureMainMenuEventTest.php @@ -12,23 +12,11 @@ namespace App\Tests\Event; use App\Event\ConfigureMainMenuEvent; use App\Utils\MenuItemModel; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; #[CoversClass(ConfigureMainMenuEvent::class)] class ConfigureMainMenuEventTest extends TestCase { - /** - * @deprecated - */ - #[Group('legacy')] - public function testLegacy(): void - { - $sut = new ConfigureMainMenuEvent(); - - self::assertEquals('apps', $sut->getAppsMenu()->getIdentifier()); - } - public function testGetterAndSetter(): void { $sut = new ConfigureMainMenuEvent(); diff --git a/tests/Event/ThemeJavascriptTranslationsEventTest.php b/tests/Event/ThemeJavascriptTranslationsEventTest.php deleted file mode 100644 index f146cfa02..000000000 --- a/tests/Event/ThemeJavascriptTranslationsEventTest.php +++ /dev/null @@ -1,43 +0,0 @@ -getTranslations()); // @phpstan-ignore method.deprecatedClass - } - - public function testGetterAndSetter(): void - { - $sut = new ThemeJavascriptTranslationsEvent(); // @phpstan-ignore new.deprecatedClass - $sut->setTranslation('foo', 'bar'); // @phpstan-ignore method.deprecatedClass - $sut->setTranslation('hello', 'world', 'testing'); // @phpstan-ignore method.deprecatedClass - - $result = $sut->getTranslations(); // @phpstan-ignore method.deprecatedClass - self::assertCount(self::COUNTER + 2, $result); - self::assertArrayHasKey('foo', $result); - self::assertEquals(['bar', 'messages'], $result['foo']); - self::assertArrayHasKey('hello', $result); - self::assertEquals(['world', 'testing'], $result['hello']); - } -} diff --git a/tests/Event/WorkingTimeApproveMonthEventTest.php b/tests/Event/WorkingTimeApproveMonthEventTest.php index 29be8690b..db4d9f171 100644 --- a/tests/Event/WorkingTimeApproveMonthEventTest.php +++ b/tests/Event/WorkingTimeApproveMonthEventTest.php @@ -26,7 +26,6 @@ class WorkingTimeApproveMonthEventTest extends TestCase $sut = new WorkingTimeApproveMonthEvent($approvalMonth, $approver); - self::assertSame($user, $sut->getUser()); // @phpstan-ignore method.deprecated self::assertSame($approvalMonth, $sut->getMonth()); self::assertSame($approver, $sut->getApprovedBy()); } diff --git a/tests/EventSubscriber/UserPreferenceSubscriberTest.php b/tests/EventSubscriber/UserPreferenceSubscriberTest.php index e0eeaca62..49fb71e1f 100644 --- a/tests/EventSubscriber/UserPreferenceSubscriberTest.php +++ b/tests/EventSubscriber/UserPreferenceSubscriberTest.php @@ -34,7 +34,6 @@ class UserPreferenceSubscriberTest extends TestCase 'calendar_initial_view', 'login_initial_view', 'daily_stats', - 'export_decimal', 'favorite_routes', ]; diff --git a/tests/Export/Base/CsvRendererTest.php b/tests/Export/Base/CsvRendererTest.php index 3debb0380..c0846849a 100644 --- a/tests/Export/Base/CsvRendererTest.php +++ b/tests/Export/Base/CsvRendererTest.php @@ -77,17 +77,17 @@ class CsvRendererTest extends AbstractRendererTestCase ]; return [ - ['400', '2437.12', '1947.99', 7, 6, 1, 2, 2, false, null, $en], - ['400', '2437.12', '1947.99', 7, 6, 1, 2, 2, true, 'de', $de] + ['1947.99', 7, 6, 1, 2, 2, null, $en], + ['1947.99', 7, 6, 1, 2, 2, 'de', $de] ]; } #[DataProvider('getTestModel')] - public function testRender(string $totalDuration, string $totalRate, string $expectedRate, int $expectedRows, int $expectedDescriptions, int $expectedUser1, int $expectedUser2, int $expectedUser3, bool $exportDecimal, ?string $locale, array $header): void + public function testRender(string $expectedRate, int $expectedRows, int $expectedDescriptions, int $expectedUser1, int $expectedUser2, int $expectedUser3, ?string $locale, array $header): void { $sut = $this->getAbstractRenderer($locale); - $response = $this->render($sut, $exportDecimal); + $response = $this->render($sut); self::assertInstanceOf(BinaryFileResponse::class, $response); $file = $response->getFile(); @@ -127,8 +127,7 @@ class CsvRendererTest extends AbstractRendererTestCase '2019-06-16', '12:00', '12:06', - ($exportDecimal ? '0.11' : '0:06'), - //'0.11', + '0.11', 'EUR', '0', '0', @@ -163,8 +162,7 @@ class CsvRendererTest extends AbstractRendererTestCase '2019-06-16', '12:00', '12:06', - ($exportDecimal ? '0.11' : '0:06'), - //'0.11', + '0.11', 'EUR', '0', '0', diff --git a/tests/Export/Base/DefaultRendererTest.php b/tests/Export/Base/DefaultRendererTest.php new file mode 100644 index 000000000..a7ae37b46 --- /dev/null +++ b/tests/Export/Base/DefaultRendererTest.php @@ -0,0 +1,128 @@ +createMock(ExportTemplateRepository::class); + $repository->expects($this->once())->method('findAll')->willReturn([]); + $logger = $this->createMock(LoggerInterface::class); + + return new ServiceExport( + $this->createMock(EventDispatcherInterface::class), + (new HtmlRendererFactoryMock($this))->create(), + (new PdfRendererFactoryMock($this))->create(), + (new CsvRendererFactoryMock($this))->create(), + (new XlsxRendererFactoryMock($this))->create(), + $repository, + $logger, + ); + } + + public function testRenderDefaultTemplates(): void + { + $sut = $this->createServiceExport(); + + $renderer = $sut->getRenderer(); + self::assertCount(4, $renderer); + self::assertInstanceOf(CsvRenderer::class, $renderer[0]); + self::assertInstanceOf(XlsxRenderer::class, $renderer[1]); + self::assertInstanceOf(PDFRenderer::class, $renderer[2]); + self::assertInstanceOf(HtmlRenderer::class, $renderer[3]); + + // make sure that the default templates do NOT violate the Twig SecurityPolicy + $response = $this->render($renderer[0]); + self::assertEquals('text/csv', $response->headers->get('Content-Type')); + self::assertStringContainsString('attachment; filename', $response->headers->get('Content-Disposition') ?? ''); + + $response = $this->render($renderer[1]); + self::assertEquals('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', $response->headers->get('Content-Type') ?? ''); + self::assertStringContainsString('attachment; filename', $response->headers->get('Content-Disposition') ?? ''); + + $response = $this->render($renderer[2]); + self::assertEquals('application/pdf', $response->headers->get('Content-Type') ?? ''); + self::assertStringContainsString('attachment; filename', $response->headers->get('Content-Disposition') ?? ''); + + $response = $this->render($renderer[3]); + self::assertEquals('text/html', $response->headers->get('Content-Type') ?? ''); + // HTML is attached to the body and twig is a mock in this setupo, so we just receive an empty string + } + + public function testRenderCustomTemplates(): void + { + $searchDir = __DIR__ . '/../../../var/templates'; + if (!is_dir($searchDir)) { + $this->expectNotToPerformAssertions(); + + return; + } + + $finder = new Finder(); + $finder + ->in($searchDir) + ->name('*.twig') + ->path('export-tpl/') + ->files() + ; + + $files = []; + $dirs = []; + foreach ($finder->getIterator() as $filename => $splFile) { + $files[] = $splFile->getRealPath(); + $dir = \dirname($splFile->getRealPath()); + $dirs[$dir] = $dir; + } + $dirs = array_keys($dirs); + + if (\count($dirs) === 0) { + $this->expectNotToPerformAssertions(); + + return; + } + + $sut = $this->createServiceExport(); + foreach ($dirs as $dir) { + $sut->addDirectory($dir); + } + + $renderers = $sut->getRenderer(); + self::assertCount(4 + \count($files), $renderers); + foreach ($renderers as $renderer) { + $response = $this->render($renderer); + self::assertInstanceOf(Response::class, $response); + } + } +} diff --git a/tests/Export/Base/HtmlRendererTest.php b/tests/Export/Base/HtmlRendererTest.php index 0895a7eb5..4dcd8f39c 100644 --- a/tests/Export/Base/HtmlRendererTest.php +++ b/tests/Export/Base/HtmlRendererTest.php @@ -45,17 +45,7 @@ class HtmlRendererTest extends AbstractRendererTestCase self::assertEquals('foo', $sut->getId()); self::assertEquals('bar', $sut->getTitle()); self::assertEquals('html', $sut->getType()); - self::assertFalse($sut->isInternal()); - } - - #[Group('legacy')] - public function testLegacy(): void - { - $sut = $this->getAbstractRenderer(); - - $sut->setTemplate('some'); // @phpstan-ignore method.deprecated - $sut->setId('xxxxxx'); // @phpstan-ignore method.deprecated - self::assertEquals('xxxxxx', $sut->getId()); + self::assertFalse($sut->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } public function testRender(): void diff --git a/tests/Export/Base/PdfRendererTest.php b/tests/Export/Base/PdfRendererTest.php index 74c4532c2..839a7e59c 100644 --- a/tests/Export/Base/PdfRendererTest.php +++ b/tests/Export/Base/PdfRendererTest.php @@ -26,7 +26,7 @@ use Twig\Environment; #[Group('integration')] class PdfRendererTest extends AbstractRendererTestCase { - protected function getAbstractRenderer(bool $exportDecimal = false): PDFRenderer + protected function getAbstractRenderer(): PDFRenderer { $twig = $this->createMock(Environment::class); $converter = $this->createMock(HtmlToPdfConverter::class); @@ -55,17 +55,7 @@ class PdfRendererTest extends AbstractRendererTestCase self::assertEquals(['foo' => 'bar2'], $sut->getPdfOptions()); $sut->setPdfOption('hello', 'world'); self::assertEquals(['foo' => 'bar2', 'hello' => 'world'], $sut->getPdfOptions()); - self::assertFalse($sut->isInternal()); - } - - #[Group('legacy')] - public function testLegacy(): void - { - $sut = $this->getAbstractRenderer(); - - $sut->setTemplate('some'); // @phpstan-ignore method.deprecated - $sut->setTitle('xxxxxx'); // @phpstan-ignore method.deprecated - self::assertEquals('xxxxxx', $sut->getTitle()); + self::assertFalse($sut->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } public function testRender(): void diff --git a/tests/Export/Base/PdfTemplateRendererTest.php b/tests/Export/Base/PdfTemplateRendererTest.php index 5e2da92f6..6d4bd489a 100644 --- a/tests/Export/Base/PdfTemplateRendererTest.php +++ b/tests/Export/Base/PdfTemplateRendererTest.php @@ -71,7 +71,7 @@ class PdfTemplateRendererTest extends AbstractRendererTestCase self::assertEquals('test', $sut->getId()); self::assertEquals('bar', $sut->getTitle()); self::assertEquals('pdf', $sut->getType()); - self::assertTrue($sut->isInternal()); + self::assertTrue($sut->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } public function testDefaultTemplateRender(): void @@ -95,7 +95,7 @@ class PdfTemplateRendererTest extends AbstractRendererTestCase 'date', 'begin', 'end', - 'duration', + 'duration_decimal', 'currency', 'rate', 'internal_rate', diff --git a/tests/Export/ColumnConverterTest.php b/tests/Export/ColumnConverterTest.php index 0978e65df..a68da0d99 100644 --- a/tests/Export/ColumnConverterTest.php +++ b/tests/Export/ColumnConverterTest.php @@ -51,7 +51,7 @@ class ColumnConverterTest extends TestCase 'date', 'begin', 'end', - 'duration', + 'duration_decimal', 'currency', 'rate', 'internal_rate', @@ -99,7 +99,7 @@ class ColumnConverterTest extends TestCase 'date', 'begin', 'end', - 'duration', + 'duration_decimal', 'user.alias', 'user.name', 'user.email', @@ -164,7 +164,7 @@ class ColumnConverterTest extends TestCase 'date', 'begin', 'end', - 'duration', + 'duration_decimal', 'user.alias', 'user.name', 'user.email', diff --git a/tests/Export/DefaultTemplateTest.php b/tests/Export/DefaultTemplateTest.php index c70786f6d..96e55734f 100644 --- a/tests/Export/DefaultTemplateTest.php +++ b/tests/Export/DefaultTemplateTest.php @@ -9,7 +9,6 @@ namespace App\Tests\Export; -use App\Entity\User; use App\Export\DefaultTemplate; use App\Repository\Query\TimesheetQuery; use App\Tests\Mocks\MetaFieldColumnSubscriberMock; @@ -33,7 +32,7 @@ class DefaultTemplateTest extends TestCase 'date', 'begin', 'end', - 'duration', + 'duration_decimal', 'currency', 'rate', 'internal_rate', @@ -59,7 +58,7 @@ class DefaultTemplateTest extends TestCase self::assertEquals($columns, $template->getColumns(new TimesheetQuery())); } - public function testFullConstructorWithDecimalDurationAndMetaColumns(): void + public function testFullConstructorWithMetaColumns(): void { $dispatcher = new EventDispatcher(); $dispatcher->addSubscriber(new MetaFieldColumnSubscriberMock()); @@ -70,11 +69,6 @@ class DefaultTemplateTest extends TestCase self::assertNull($template->getLocale()); self::assertEquals([], $template->getOptions()); - $user = new User(); - $user->setPreferenceValue('export_decimal', true); - $query = new TimesheetQuery(); - $query->setCurrentUser($user); - $columns = [ 'date', 'begin', @@ -109,6 +103,6 @@ class DefaultTemplateTest extends TestCase 'activity.meta.activity-foo', 'user.meta.mypref', ]; - self::assertEquals($columns, $template->getColumns($query)); + self::assertEquals($columns, $template->getColumns(new TimesheetQuery())); } } diff --git a/tests/Export/ExportFilenameTest.php b/tests/Export/ExportFilenameTest.php index ae6e13e5d..952b85afb 100644 --- a/tests/Export/ExportFilenameTest.php +++ b/tests/Export/ExportFilenameTest.php @@ -61,8 +61,12 @@ class ExportFilenameTest extends TestCase $sut = new ExportFilename($query); self::assertEquals($datePrefix . '-ss_n_--Demo_ProjecT1', $sut->getFilename()); + $reflectionUser = new \ReflectionClass(User::class); + $userIdProperty = $reflectionUser->getProperty('id'); + $user = new User(); $user->setUserIdentifier('ayumi'); + $userIdProperty->setValue($user, 1); $query->addUser($user); $sut = new ExportFilename($query); @@ -71,12 +75,7 @@ class ExportFilenameTest extends TestCase $sut = new ExportFilename($query); self::assertEquals($datePrefix . '-ss_n_--Demo_ProjecT1-Martin_Muller-Ludenscheidt', $sut->getFilename()); - - $user = $this->createMock(User::class); - $user->method('getId')->willReturn(1); - $query->addUser($user); - $sut = new ExportFilename($query); - self::assertEquals($datePrefix . '-ss_n_--Demo_ProjecT1', $sut->getFilename()); + $query->removeUser($user); $project = new Project(); $project->setName('Project2'); diff --git a/tests/Export/Package/PhpOfficeSpreadsheetTest.php b/tests/Export/Package/PhpOfficeSpreadsheetTest.php index 1e18cf700..59917f94f 100644 --- a/tests/Export/Package/PhpOfficeSpreadsheetTest.php +++ b/tests/Export/Package/PhpOfficeSpreadsheetTest.php @@ -49,7 +49,6 @@ class PhpOfficeSpreadsheetTest extends TestCase $spreadsheetPackage->open($this->filename); $reflection = new \ReflectionClass($spreadsheetPackage); $property = $reflection->getProperty('filename'); - $property->setAccessible(true); self::assertEquals($this->filename, $property->getValue($spreadsheetPackage)); } @@ -93,7 +92,6 @@ class PhpOfficeSpreadsheetTest extends TestCase $reflection = new \ReflectionClass($spreadsheetPackage); $property = $reflection->getProperty('worksheet'); - $property->setAccessible(true); /** @var Worksheet $worksheet */ $worksheet = $property->getValue($spreadsheetPackage); @@ -110,7 +108,6 @@ class PhpOfficeSpreadsheetTest extends TestCase $reflection = new \ReflectionClass($spreadsheetPackage); $property = $reflection->getProperty('worksheet'); - $property->setAccessible(true); /** @var Worksheet $worksheet */ $worksheet = $property->getValue($spreadsheetPackage); diff --git a/tests/Export/Renderer/AbstractRendererTestCase.php b/tests/Export/Renderer/AbstractRendererTestCase.php index 6a991eb69..6bc227519 100644 --- a/tests/Export/Renderer/AbstractRendererTestCase.php +++ b/tests/Export/Renderer/AbstractRendererTestCase.php @@ -26,12 +26,25 @@ use Symfony\Component\HttpFoundation\Response; abstract class AbstractRendererTestCase extends KernelTestCase { - protected function render(ExportRendererInterface $renderer, bool $exportDecimal = false): Response + protected function render(ExportRendererInterface $renderer): Response { + $reflectionUser = new \ReflectionClass(User::class); + $userIdProperty = $reflectionUser->getProperty('id'); + + $reflectionCustomer = new \ReflectionClass(Customer::class); + $customerIdProperty = $reflectionCustomer->getProperty('id'); + + $reflectionProject = new \ReflectionClass(Project::class); + $projectIdProperty = $reflectionProject->getProperty('id'); + + $reflectionActivity = new \ReflectionClass(Activity::class); + $activityIdProperty = $reflectionActivity->getProperty('id'); + $customer = new Customer('Customer Name'); $customer->setNumber('A-0123456789'); $customer->setVatId('DE-9876543210'); $customer->setMetaField((new CustomerMeta())->setName('customer-foo')->setValue('customer-bar')->setIsVisible(true)); + $customerIdProperty->setValue($customer, 1); $project = new Project(); $project->setName('project name'); @@ -39,25 +52,23 @@ abstract class AbstractRendererTestCase extends KernelTestCase $project->setOrderNumber('ORDER-123'); $project->setMetaField((new ProjectMeta())->setName('project-bar')->setValue('project-bar')->setIsVisible(true)); $project->setMetaField((new ProjectMeta())->setName('project-foo2')->setValue('project-foo2')->setIsVisible(true)); + $projectIdProperty->setValue($project, 1); $activity = new Activity(); $activity->setName('activity description'); $activity->setProject($project); $activity->setMetaField((new ActivityMeta())->setName('activity-foo')->setValue('activity-bar')->setIsVisible(true)); + $activityIdProperty->setValue($activity, 1); - $userMethods = ['getId', 'getPreferenceValue', 'getUsername', 'getUserIdentifier', 'getAlias']; - $user1 = $this->getMockBuilder(User::class)->onlyMethods($userMethods)->disableOriginalConstructor()->getMock(); - $user1->method('getId')->willReturn(1); - $user1->method('getPreferenceValue')->willReturn('50'); - $user1->method('getAlias')->willReturn('Foo Bar'); - $user1->method('getUserIdentifier')->willReturn('foo-bar'); - $user1->method('getUsername')->willReturn('foo-bar'); + $user1 = new User(); + $user1->setUserIdentifier('foo-bar'); + $user1->setAlias('Foo Bar'); + $userIdProperty->setValue($user1, 1); - $user2 = $this->getMockBuilder(User::class)->onlyMethods($userMethods)->disableOriginalConstructor()->getMock(); - $user2->method('getId')->willReturn(2); - $user2->method('getAlias')->willReturn('Hello World'); - $user2->method('getUserIdentifier')->willReturn('hello-world'); - $user2->method('getUsername')->willReturn('hello-world'); + $user2 = new User(); + $user2->setAlias('Hello World'); + $user2->setUserIdentifier('hello-world'); + $userIdProperty->setValue($user2, 2); $timesheet = new Timesheet(); $timesheet->setDuration(3600); @@ -100,6 +111,7 @@ abstract class AbstractRendererTestCase extends KernelTestCase $userKevin = new User(); $userKevin->setAlias('Kevin'); $userKevin->setUserIdentifier('kevin'); + $userIdProperty->setValue($userKevin, 3); $timesheet5 = new Timesheet(); $timesheet5->setDuration(400); @@ -117,6 +129,7 @@ abstract class AbstractRendererTestCase extends KernelTestCase $userNivek = new User(); $userNivek->setAlias('niveK'); $userNivek->setUserIdentifier('nivek'); + $userIdProperty->setValue($userNivek, 4); $timesheet6 = new Timesheet(); $timesheet6->setDuration(400); @@ -129,15 +142,12 @@ abstract class AbstractRendererTestCase extends KernelTestCase $entries = [$timesheet, $timesheet2, $timesheet3, $timesheet4, $timesheet5, $timesheet6]; - $currentUser = $this->createMock(User::class); - $currentUser->expects($this->any())->method('isExportDecimal')->willReturn($exportDecimal); - $query = new TimesheetQuery(); $query->setActivities([$activity]); $query->setBegin(new \DateTime()); $query->setEnd(new \DateTime()); $query->setProjects([$project]); - $query->setCurrentUser($currentUser); + $query->setCurrentUser(new User()); return $renderer->render($entries, $query); } diff --git a/tests/Export/Renderer/HtmlRendererFactoryTest.php b/tests/Export/Renderer/HtmlRendererFactoryTest.php index 67e8849d2..e5ea19db7 100644 --- a/tests/Export/Renderer/HtmlRendererFactoryTest.php +++ b/tests/Export/Renderer/HtmlRendererFactoryTest.php @@ -35,6 +35,6 @@ class HtmlRendererFactoryTest extends TestCase self::assertInstanceOf(HtmlRenderer::class, $renderer); self::assertEquals('foo', $renderer->getId()); self::assertEquals('print', $renderer->getTitle()); - self::assertFalse($renderer->isInternal()); + self::assertFalse($renderer->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } } diff --git a/tests/Export/Renderer/HtmlRendererTest.php b/tests/Export/Renderer/HtmlRendererTest.php index 6936a1538..b84d46055 100644 --- a/tests/Export/Renderer/HtmlRendererTest.php +++ b/tests/Export/Renderer/HtmlRendererTest.php @@ -35,7 +35,10 @@ class HtmlRendererTest extends AbstractRendererTestCase $this->createMock(Environment::class), new EventDispatcher(), $this->createMock(ProjectStatisticService::class), - $this->createMock(ActivityStatisticService::class) + $this->createMock(ActivityStatisticService::class), + 'html', + 'print', + 'export/print.html.twig', ); self::assertEquals('html', $sut->getId()); @@ -72,7 +75,10 @@ class HtmlRendererTest extends AbstractRendererTestCase $twig, new EventDispatcher(), $this->createMock(ProjectStatisticService::class), - $this->createMock(ActivityStatisticService::class) + $this->createMock(ActivityStatisticService::class), + 'html', + 'print', + 'export/print.html.twig', ); $response = $this->render($sut); diff --git a/tests/Export/Renderer/PdfRendererFactoryTest.php b/tests/Export/Renderer/PdfRendererFactoryTest.php index 899dbaca4..ece0587da 100644 --- a/tests/Export/Renderer/PdfRendererFactoryTest.php +++ b/tests/Export/Renderer/PdfRendererFactoryTest.php @@ -29,7 +29,7 @@ class PdfRendererFactoryTest extends TestCase self::assertInstanceOf(PDFRenderer::class, $renderer); self::assertEquals('foo', $renderer->getId()); - self::assertFalse($renderer->isInternal()); + self::assertFalse($renderer->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } public function testCreateFromTemplate(): void @@ -42,6 +42,6 @@ class PdfRendererFactoryTest extends TestCase self::assertInstanceOf(PdfTemplateRenderer::class, $renderer); self::assertEquals('foo', $renderer->getId()); - self::assertTrue($renderer->isInternal()); + self::assertTrue($renderer->isInternal()); // @phpstan-ignore staticMethod.alreadyNarrowedType } } diff --git a/tests/Export/Renderer/PdfRendererTest.php b/tests/Export/Renderer/PdfRendererTest.php index 5d4e08096..32970fd29 100644 --- a/tests/Export/Renderer/PdfRendererTest.php +++ b/tests/Export/Renderer/PdfRendererTest.php @@ -33,7 +33,10 @@ class PdfRendererTest extends AbstractRendererTestCase $sut = new PDFRenderer( $this->createMock(Environment::class), $this->createMock(HtmlToPdfConverter::class), - $this->createMock(ProjectStatisticService::class) + $this->createMock(ProjectStatisticService::class), + 'pdf', + 'pdf', + 'export/pdf-layout.html.twig' ); self::assertEquals('pdf', $sut->getId()); @@ -59,7 +62,14 @@ class PdfRendererTest extends AbstractRendererTestCase $request->setLocale('en'); $stack->push($request); - $sut = new PDFRenderer($twig, $converter, $this->createMock(ProjectStatisticService::class)); + $sut = new PDFRenderer( + $twig, + $converter, + $this->createMock(ProjectStatisticService::class), + 'pdf', + 'pdf', + 'export/pdf-layout.html.twig' + ); $prefix = date('Ymd'); @@ -83,7 +93,14 @@ class PdfRendererTest extends AbstractRendererTestCase $request->setLocale('en'); $stack->push($request); - $sut = new PDFRenderer($twig, $converter, $this->createMock(ProjectStatisticService::class)); + $sut = new PDFRenderer( + $twig, + $converter, + $this->createMock(ProjectStatisticService::class), + 'pdf', + 'pdf', + 'export/pdf-layout.html.twig' + ); $prefix = date('Ymd'); diff --git a/tests/Export/ServiceExportTest.php b/tests/Export/ServiceExportTest.php index db1480c83..c16b67762 100644 --- a/tests/Export/ServiceExportTest.php +++ b/tests/Export/ServiceExportTest.php @@ -97,7 +97,10 @@ class ServiceExportTest extends TestCase $this->createMock(Environment::class), new EventDispatcher(), $this->createMock(ProjectStatisticService::class), - $this->createMock(ActivityStatisticService::class) + $this->createMock(ActivityStatisticService::class), + 'html', + 'print', + 'export/print.html.twig', ); $sut->addRenderer($renderer); @@ -116,7 +119,9 @@ class ServiceExportTest extends TestCase new EventDispatcher(), $this->createMock(ProjectStatisticService::class), $this->createMock(ActivityStatisticService::class), - 'print' + 'print', + 'print', + 'export/print.html.twig', ); $sut->addTimesheetExporter($exporter); diff --git a/tests/Export/Timesheet/AbstractRendererTestCase.php b/tests/Export/Timesheet/AbstractRendererTestCase.php index 4f68cbfe8..b69859c11 100644 --- a/tests/Export/Timesheet/AbstractRendererTestCase.php +++ b/tests/Export/Timesheet/AbstractRendererTestCase.php @@ -35,10 +35,23 @@ abstract class AbstractRendererTestCase extends KernelTestCase { protected function render(ExportRendererInterface $renderer): Response { + $reflectionUser = new \ReflectionClass(User::class); + $userIdProperty = $reflectionUser->getProperty('id'); + + $reflectionCustomer = new \ReflectionClass(Customer::class); + $customerIdProperty = $reflectionCustomer->getProperty('id'); + + $reflectionProject = new \ReflectionClass(Project::class); + $projectIdProperty = $reflectionProject->getProperty('id'); + + $reflectionActivity = new \ReflectionClass(Activity::class); + $activityIdProperty = $reflectionActivity->getProperty('id'); + $customer = new Customer('Customer Name'); $customer->setNumber('A-0123456789'); $customer->setVatId('DE-9876543210'); $customer->setMetaField((new CustomerMeta())->setName('customer-foo')->setValue('customer-bar')->setIsVisible(true)); + $customerIdProperty->setValue($customer, 1); $project = new Project(); $project->setName('project name'); @@ -46,11 +59,13 @@ abstract class AbstractRendererTestCase extends KernelTestCase $project->setOrderNumber('ORDER-123'); $project->setMetaField((new ProjectMeta())->setName('project-bar')->setValue('project-bar')->setIsVisible(true)); $project->setMetaField((new ProjectMeta())->setName('project-foo2')->setValue('project-foo2')->setIsVisible(true)); + $projectIdProperty->setValue($project, 1); $activity = new Activity(); $activity->setName('activity description'); $activity->setProject($project); $activity->setMetaField((new ActivityMeta())->setName('activity-foo')->setValue('activity-bar')->setIsVisible(true)); + $activityIdProperty->setValue($activity, 1); $userMethods = ['getId', 'getPreferenceValue', 'getUsername', 'getUserIdentifier']; $user1 = $this->getMockBuilder(User::class)->onlyMethods($userMethods)->disableOriginalConstructor()->getMock(); @@ -103,6 +118,7 @@ abstract class AbstractRendererTestCase extends KernelTestCase $user = new User(); $user->setUserIdentifier('kevin'); + $userIdProperty->setValue($user, 12); $timesheet5 = new Timesheet(); $timesheet5->setDuration(400); diff --git a/tests/Export/Timesheet/PdfRendererTest.php b/tests/Export/Timesheet/PdfRendererTest.php index 5b5f05632..50ce3855a 100644 --- a/tests/Export/Timesheet/PdfRendererTest.php +++ b/tests/Export/Timesheet/PdfRendererTest.php @@ -33,7 +33,10 @@ class PdfRendererTest extends AbstractRendererTestCase $sut = new PDFRenderer( $this->createMock(Environment::class), $this->createMock(HtmlToPdfConverter::class), - $this->createMock(ProjectStatisticService::class) + $this->createMock(ProjectStatisticService::class), + 'pdf', + 'pdf', + 'export/pdf-layout.html.twig' ); self::assertEquals('pdf', $sut->getId()); @@ -54,7 +57,14 @@ class PdfRendererTest extends AbstractRendererTestCase $request->setLocale('en'); $stack->push($request); - $sut = new PDFRenderer($twig, $converter, $this->createMock(ProjectStatisticService::class)); + $sut = new PDFRenderer( + $twig, + $converter, + $this->createMock(ProjectStatisticService::class), + 'pdf', + 'pdf', + 'export/pdf-layout.html.twig' + ); $response = $this->render($sut); diff --git a/tests/Form/DataTransformer/SearchTermTransformerTest.php b/tests/Form/DataTransformer/SearchTermTransformerTest.php index 3c4563034..68ff2ec70 100644 --- a/tests/Form/DataTransformer/SearchTermTransformerTest.php +++ b/tests/Form/DataTransformer/SearchTermTransformerTest.php @@ -44,8 +44,6 @@ class SearchTermTransformerTest extends TestCase self::assertInstanceOf(SearchTerm::class, $term); self::assertEquals('hello world:xxxxx foo bar test:1234', $term->getOriginalSearch()); - self::assertEquals('hello foo bar', $term->getSearchTerm()); - self::assertEquals(['world' => 'xxxxx', 'test' => '1234'], $term->getSearchFields()); $expectedParts = [ ['hello', null], ['xxxxx', 'world'], diff --git a/tests/Invoice/Calculator/AbstractCalculatorTestCase.php b/tests/Invoice/Calculator/AbstractCalculatorTestCase.php index a02966a8c..6c51a0795 100644 --- a/tests/Invoice/Calculator/AbstractCalculatorTestCase.php +++ b/tests/Invoice/Calculator/AbstractCalculatorTestCase.php @@ -53,7 +53,6 @@ abstract class AbstractCalculatorTestCase extends TestCase protected function assertTax(CalculatorInterface $sut, int $rate): void { - self::assertEquals($rate, $sut->getVat()); // @phpstan-ignore method.deprecated $rows = $sut->getTaxRows(); self::assertCount(1, $rows); @@ -74,7 +73,7 @@ abstract class AbstractCalculatorTestCase extends TestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php index fd9f97cd1..5ee0f259c 100644 --- a/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ActivityInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class ActivityInvoiceCalculatorTest extends AbstractCalculatorTestCase $date = new \DateTime(); $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php index 005a1c2a5..4b04bf614 100644 --- a/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ActivityUserInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class ActivityUserInvoiceCalculatorTest extends AbstractCalculatorTestCase $date = new \DateTime(); $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user1->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php b/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php index 8112103b7..34ee59a94 100644 --- a/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/DateInvoiceCalculatorTest.php @@ -42,7 +42,7 @@ class DateInvoiceCalculatorTest extends AbstractCalculatorTestCase $date = new DateTime(); $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php index e4b7d6609..eeb69ea8c 100644 --- a/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/DateUserInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class DateUserInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user1->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/DefaultCalculatorTest.php b/tests/Invoice/Calculator/DefaultCalculatorTest.php index 5142e2916..0a11e5827 100644 --- a/tests/Invoice/Calculator/DefaultCalculatorTest.php +++ b/tests/Invoice/Calculator/DefaultCalculatorTest.php @@ -36,7 +36,7 @@ class DefaultCalculatorTest extends AbstractCalculatorTestCase $date = new \DateTime(); $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $timesheet = new Timesheet(); $timesheet->setDescription('foo 1'); diff --git a/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php b/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php index ab02e6248..588ea69bb 100644 --- a/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/PriceInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class PriceInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ProjectActivityInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectActivityInvoiceCalculatorTest.php index 86b5c33ba..a449f2cf9 100644 --- a/tests/Invoice/Calculator/ProjectActivityInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ProjectActivityInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class ProjectActivityInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user1->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php index aa654f560..9e80d7bb6 100644 --- a/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ProjectInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class ProjectInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php index fe88b7836..341d2c5bd 100644 --- a/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ProjectUserInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class ProjectUserInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user1 = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user1->method('getId')->willReturn(1); diff --git a/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php b/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php index 1efa8bf6c..71ad7ede7 100644 --- a/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/ShortInvoiceCalculatorTest.php @@ -40,7 +40,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $project = new Project(); $project->setName('sdfsdf'); @@ -119,7 +119,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $project = new Project(); $project->setName('sdfsdf'); @@ -191,7 +191,7 @@ class ShortInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $project = new Project(); $project->setName('sdfsdf'); diff --git a/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php b/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php index 176d7e3b0..24b802cee 100644 --- a/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/UserInvoiceCalculatorTest.php @@ -38,7 +38,7 @@ class UserInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $activity = new Activity(); $activity->setName('activity description'); diff --git a/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php b/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php index 81d285236..43756ffe2 100644 --- a/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php +++ b/tests/Invoice/Calculator/WeeklyInvoiceCalculatorTest.php @@ -41,7 +41,7 @@ class WeeklyInvoiceCalculatorTest extends AbstractCalculatorTestCase { $customer = new Customer('foo'); $template = new InvoiceTemplate(); - $template->setVat(19); + $template->setTaxRate(19.0); $user = $this->getMockBuilder(User::class)->onlyMethods(['getId'])->disableOriginalConstructor()->getMock(); $user->method('getId')->willReturn(1); diff --git a/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php b/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php index b233781cd..8d2a18479 100644 --- a/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php +++ b/tests/Invoice/Hydrator/InvoiceModelCustomerHydratorTest.php @@ -34,7 +34,7 @@ class InvoiceModelCustomerHydratorTest extends TestCase $this->assertModelStructure($result); self::assertEquals([ - 'customer.id' => null, + 'customer.id' => 120, 'customer.address' => "Foo\nStreet\n1111 City", 'customer.address_line1' => '', 'customer.address_line2' => '', diff --git a/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php b/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php index 967526570..e499cf0ce 100644 --- a/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php +++ b/tests/Invoice/Hydrator/InvoiceModelDefaultHydratorTest.php @@ -39,7 +39,6 @@ class InvoiceModelDefaultHydratorTest extends TestCase $obj = new ReflectionObject($model); $prop = $obj->getProperty('calculator'); - $prop->setAccessible(true); $prop->setValue($model, null); $sut = new InvoiceModelDefaultHydrator(); diff --git a/tests/Invoice/Hydrator/InvoiceModelIssuerHydratorTest.php b/tests/Invoice/Hydrator/InvoiceModelIssuerHydratorTest.php index adc91837d..415ff705e 100644 --- a/tests/Invoice/Hydrator/InvoiceModelIssuerHydratorTest.php +++ b/tests/Invoice/Hydrator/InvoiceModelIssuerHydratorTest.php @@ -33,7 +33,7 @@ class InvoiceModelIssuerHydratorTest extends TestCase $this->assertModelStructure($result); self::assertEquals([ - 'issuer.id' => null, + 'issuer.id' => 120, 'issuer.address' => "Foo\nStreet\n1111 City", 'issuer.address_line1' => '', 'issuer.address_line2' => '', diff --git a/tests/Invoice/InvoiceItemTest.php b/tests/Invoice/InvoiceItemTest.php index a275a4245..c3276eea8 100644 --- a/tests/Invoice/InvoiceItemTest.php +++ b/tests/Invoice/InvoiceItemTest.php @@ -25,7 +25,7 @@ class InvoiceItemTest extends TestCase self::assertNull($sut->getFixedRate()); self::assertNull($sut->getEnd()); self::assertEquals(0.00, $sut->getRate()); - self::assertEquals(0.00, $sut->getInternalRate()); // @phpstan-ignore method.deprecated + self::assertEquals(0.00, $sut->getInternalRate()); self::assertEquals(0.00, $sut->getAppliedRate()); self::assertNull($sut->getProject()); self::assertIsArray($sut->getAdditionalFields()); diff --git a/tests/Invoice/InvoiceModelTest.php b/tests/Invoice/InvoiceModelTest.php index b3dd3be71..65c005360 100644 --- a/tests/Invoice/InvoiceModelTest.php +++ b/tests/Invoice/InvoiceModelTest.php @@ -30,7 +30,6 @@ class InvoiceModelTest extends TestCase self::assertNotNull($sut->getQuery()); self::assertFalse($sut->isPreview()); - self::assertFalse($sut->isHideZeroTax()); self::assertNull($sut->getCalculator()); self::assertEmpty($sut->getEntries()); self::assertIsArray($sut->getEntries()); @@ -45,9 +44,7 @@ class InvoiceModelTest extends TestCase self::assertEquals([], $sut->getOptions()); $sut->setPreview(true); - $sut->setHideZeroTax(true); self::assertTrue($sut->isPreview()); - self::assertTrue($sut->isHideZeroTax()); } public function testEmptyObjectThrowsExceptionOnNumberGenerator(): void diff --git a/tests/Invoice/Renderer/DebugRendererTest.php b/tests/Invoice/Renderer/DebugRendererTest.php index 484a5336e..888f44a6a 100644 --- a/tests/Invoice/Renderer/DebugRendererTest.php +++ b/tests/Invoice/Renderer/DebugRendererTest.php @@ -14,10 +14,12 @@ use App\Invoice\InvoiceItemHydrator; use App\Invoice\InvoiceModel; use App\Invoice\InvoiceModelHydrator; use App\Model\InvoiceDocument; +use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use Symfony\Component\HttpFoundation\Response; +#[CoversClass(DebugRenderer::class)] class DebugRendererTest extends TestCase { use RendererTestTrait; diff --git a/tests/Invoice/Renderer/PdfRendererTest.php b/tests/Invoice/Renderer/PdfRendererTest.php index e95878ffa..2b5a524c7 100644 --- a/tests/Invoice/Renderer/PdfRendererTest.php +++ b/tests/Invoice/Renderer/PdfRendererTest.php @@ -18,6 +18,7 @@ use App\Tests\Mocks\FileHelperFactory; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Group; use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; +use Symfony\Component\Finder\Finder; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RequestStack; use Twig\Environment; @@ -118,12 +119,26 @@ class PdfRendererTest extends KernelTestCase $dirs = [ __DIR__ . '/../../../templates/invoice/renderer/', - //__DIR__ . '/../../../var/invoices/', - //__DIR__ . '/../../../var/invoices_customer/', - //__DIR__ . '/../../../var/invoices_old/', ]; $files = []; + + $additionalTemplatesDir = __DIR__ . '/../../../var/templates'; + if (is_dir($additionalTemplatesDir)) { + $finder = new Finder(); + $finder + ->in($additionalTemplatesDir) + ->name('*.pdf.twig') + ->path('invoice-tpl/') + ->files(); + + foreach ($finder->getIterator() as $splFile) { + $filename = $splFile->getRealPath(); + $files[] = $filename; + $loader->addPath(\dirname($filename) . '/', 'invoice'); + } + } + foreach ($dirs as $dir) { if (!is_dir($dir)) { continue; @@ -145,7 +160,6 @@ class PdfRendererTest extends KernelTestCase $response = $sut->render($document, $model); self::assertEquals('application/pdf', $response->headers->get('Content-Type')); self::assertStringContainsString('attachment; filename', $response->headers->get('Content-Disposition')); - self::assertNotEmpty($response->getContent()); } } } diff --git a/tests/Invoice/Renderer/RendererTestTrait.php b/tests/Invoice/Renderer/RendererTestTrait.php index 5180d6012..5ef1357bb 100644 --- a/tests/Invoice/Renderer/RendererTestTrait.php +++ b/tests/Invoice/Renderer/RendererTestTrait.php @@ -32,7 +32,6 @@ use App\Model\InvoiceDocument; use App\Repository\InvoiceRepository; use App\Repository\Query\InvoiceQuery; use App\Tests\Mocks\InvoiceModelFactoryFactory; -use Doctrine\Common\Collections\ArrayCollection; trait RendererTestTrait { @@ -85,6 +84,11 @@ trait RendererTestTrait protected function getInvoiceModel(): InvoiceModel { + $customerId = new \ReflectionProperty(Customer::class, 'id'); + $activityId = new \ReflectionProperty(Activity::class, 'id'); + $projectId = new \ReflectionProperty(Project::class, 'id'); + $userId = new \ReflectionProperty(User::class, 'id'); + $user = new User(); $user->setUserIdentifier('one-user'); $user->setTitle('user title'); @@ -92,74 +96,71 @@ trait RendererTestTrait $user->setEmail('fantastic@four'); $user->addPreference(new UserPreference('kitty', 'kat')); $user->addPreference(new UserPreference('hello', 'world')); + $userId->setValue($user, 120); $customer = new Customer('customer,with/special#name'); $customer->setAddress('Foo' . PHP_EOL . 'Street' . PHP_EOL . '1111 City'); $customer->setCurrency('EUR'); $customer->setCountry('AT'); $customer->setMetaField((new CustomerMeta())->setName('foo-customer')->setValue('bar-customer')->setIsVisible(true)); + $customerId->setValue($customer, 120); $template = new InvoiceTemplate(); $template->setTitle('a very *long* test invoice / template title with [ßpecial] chäracter'); - $template->setVat(19); + $template->setTaxRate(19.0); $template->setLanguage('en'); $template->setCustomer($customer); $pMeta = new ProjectMeta(); $pMeta->setName('foo-project')->setValue('bar-project')->setIsVisible(true); - $project = $this->createMock(Project::class); - $project->method('getId')->willReturn(0); - $project->method('getName')->willReturn('project name'); - $project->method('getCustomer')->willReturn($customer); - $project->method('getMetaFields')->willReturn(new ArrayCollection([$pMeta])); - $project->method('getVisibleMetaFields')->willReturn([$pMeta]); + $project = new Project(); + $projectId->setValue($project, 0); + $project->setName('project name'); + $project->setCustomer($customer); + $project->setMetaField($pMeta); $aMeta = new ActivityMeta(); $aMeta->setName('foo-activity'); $aMeta->setValue('bar-activity'); $aMeta->setIsVisible(true); - $activity = $this->createMock(Activity::class); - $activity->method('getId')->willReturn(0); - $activity->method('getName')->willReturn('activity description'); - $activity->method('getProject')->willReturn($project); - $activity->method('getMetaFields')->willReturn(new ArrayCollection([$aMeta])); - $activity->method('getVisibleMetaFields')->willReturn([$aMeta]); + $activity = new Activity(); + $activityId->setValue($activity, 0); + $activity->setName('activity description'); + $activity->setProject($project); + $activity->setMetaField($aMeta); $pMeta2 = new ProjectMeta(); $pMeta2->setName('foo-project')->setValue('bar-project2')->setIsVisible(true); - $project2 = $this->createMock(Project::class); - $project2->method('getId')->willReturn(1); - $project2->method('getName')->willReturn('project 2 name'); - $project2->method('getCustomer')->willReturn($customer); - $project2->method('getMetaFields')->willReturn(new ArrayCollection([$pMeta2])); - $project2->method('getVisibleMetaFields')->willReturn([$pMeta2]); + $project2 = new Project(); + $projectId->setValue($project2, 1); + $project2->setName('project 2 name'); + $project2->setCustomer($customer); + $project2->setMetaField($pMeta2); $aMeta2 = new ActivityMeta(); $aMeta2->setName('foo-activity'); $aMeta2->setValue('bar-activity2'); $aMeta2->setIsVisible(true); - $activity2 = $this->createMock(Activity::class); - $activity2->method('getId')->willReturn(1); - $activity2->method('getName')->willReturn('activity 1 description'); - $activity2->method('getProject')->willReturn($project2); - $activity2->method('getMetaFields')->willReturn(new ArrayCollection([$aMeta2])); - $activity2->method('getVisibleMetaFields')->willReturn([$aMeta2]); + $activity2 = new Activity(); + $activityId->setValue($activity2, 1); + $activity2->setName('activity 1 description'); + $activity2->setProject($project2); + $activity2->setMetaField($aMeta2); $pref1 = new UserPreference('foo', 'bar'); $pref2 = new UserPreference('mad', 123.45); - $userMethods = ['getId', 'getPreferenceValue', 'getVisiblePreferences', 'getUsername', 'getUserIdentifier']; - $user1 = $this->getMockBuilder(User::class)->onlyMethods($userMethods)->disableOriginalConstructor()->getMock(); - $user1->method('getId')->willReturn(1); - $user1->method('getPreferenceValue')->willReturn('50'); - $user1->method('getUsername')->willReturn('foo-bar'); - $user1->method('getUserIdentifier')->willReturn('foo-bar'); - $user1->method('getVisiblePreferences')->willReturn([$pref1, $pref2]); + $user1 = new User(); + $user1->setUserIdentifier('foo-bar'); + $userId->setValue($user1, 1); + //$user1->method('getPreferenceValue')->willReturn('50'); + $user1->addPreference($pref1); + $user1->addPreference($pref2); - $user2 = $this->createMock(User::class); - $user2->method('getId')->willReturn(2); - $user2->method('getUsername')->willReturn('hello-world'); - $user2->method('getUserIdentifier')->willReturn('hello-world'); - $user2->method('getVisiblePreferences')->willReturn([$pref1, $pref2]); + $user2 = new User(); + $userId->setValue($user2, 2); + $user2->setUserIdentifier('hello-world'); + $user2->addPreference($pref1); + $user2->addPreference($pref2); $timesheet = new Timesheet(); $timesheet->setDuration(3600); @@ -215,6 +216,7 @@ trait RendererTestTrait $userKevin->setUserIdentifier('kevin'); $userKevin->addPreference($pref1); $userKevin->addPreference($pref2); + $userId->setValue($userKevin, 123); $timesheet5 = new Timesheet(); $timesheet5->setDuration(400); @@ -271,6 +273,10 @@ trait RendererTestTrait protected function getInvoiceModelOneEntry(): InvoiceModel { + $customerId = new \ReflectionProperty(Customer::class, 'id'); + $activityId = new \ReflectionProperty(Activity::class, 'id'); + $userId = new \ReflectionProperty(User::class, 'id'); + $user = new User(); $user->setUserIdentifier('one-user'); $user->setTitle('user title'); @@ -278,15 +284,17 @@ trait RendererTestTrait $user->setEmail('fantastic@four'); $user->addPreference(new UserPreference('kitty', 'kat')); $user->addPreference(new UserPreference('hello', 'world')); + $userId->setValue($user, 1); $customer = new Customer('customer,with/special#name'); $customer->setCountry('DE'); $customer->setCurrency('USD'); $customer->setMetaField((new CustomerMeta())->setName('foo-customer')->setValue('bar-customer')->setIsVisible(true)); + $customerId->setValue($customer, 1); $template = new InvoiceTemplate(); $template->setTitle('a test invoice template title'); - $template->setVat(19); + $template->setTaxRate(19.0); $template->setLanguage('it'); $template->setCustomer($customer); @@ -299,15 +307,18 @@ trait RendererTestTrait $activity->setName('activity description'); $activity->setProject($project); $activity->setMetaField((new ActivityMeta())->setName('foo-activity')->setValue('bar-activity')->setIsVisible(true)); + $activityId->setValue($activity, 1); $pref1 = new UserPreference('foo', 'bar'); $pref2 = new UserPreference('mad', 123.45); - $user1 = $this->createMock(User::class); - $user1->method('getId')->willReturn(1); - $user1->method('getPreferenceValue')->willReturn('50'); - $user1->method('getUsername')->willReturn('foo-bar'); - $user1->method('getUserIdentifier')->willReturn('foo-bar'); - $user1->method('getVisiblePreferences')->willReturn([$pref1, $pref2]); + + $userId = new \ReflectionProperty(User::class, 'id'); + $user1 = new User(); + $user1->setUserIdentifier('foo-bar'); + $user1->addPreference($pref1); + $user1->addPreference($pref2); + $userId->setValue($user1, 1); + //$user1->method('getPreferenceValue')->willReturn('50'); $timesheet = new Timesheet(); $timesheet->setDuration(3600); diff --git a/tests/Invoice/ServiceInvoiceTest.php b/tests/Invoice/ServiceInvoiceTest.php index 5e41f68fc..81c82e8bc 100644 --- a/tests/Invoice/ServiceInvoiceTest.php +++ b/tests/Invoice/ServiceInvoiceTest.php @@ -34,6 +34,17 @@ use Twig\Environment; #[CoversClass(ServiceInvoice::class)] class ServiceInvoiceTest extends TestCase { + private function getCustomer(string $name, int $id): Customer + { + $customer = new Customer($name); + + $reflectionCustomer = new \ReflectionClass(Customer::class); + $customerIdProperty = $reflectionCustomer->getProperty('id'); + $customerIdProperty->setValue($customer, $id); + + return $customer; + } + private function getSut(array $paths): ServiceInvoice { $languages = [ @@ -108,7 +119,7 @@ class ServiceInvoiceTest extends TestCase $this->expectExceptionMessage('Cannot create invoice model without template'); $query = new InvoiceQuery(); - $query->setCustomers([new Customer('foo')]); + $query->setCustomers([$this->getCustomer('foo', 1)]); $sut = $this->getSut([]); $sut->createModel($query); @@ -121,7 +132,7 @@ class ServiceInvoiceTest extends TestCase $template->setLanguage('it'); $query = new InvoiceQuery(); - $query->setCustomers([new Customer('foo')]); + $query->setCustomers([$this->getCustomer('foo', 1)]); $query->setTemplate($template); $sut = $this->getSut([]); @@ -136,7 +147,7 @@ class ServiceInvoiceTest extends TestCase public function testBeginAndEndDateFallback(): void { $timezone = new \DateTimeZone('Europe/Vienna'); - $customer = new Customer('foo'); + $customer = $this->getCustomer('foo', 1); $project = new Project(); $project->setCustomer($customer); @@ -178,8 +189,10 @@ class ServiceInvoiceTest extends TestCase $template->setNumberGenerator('date'); $template->setLanguage('de'); + $customer = $this->getCustomer('foo', 1); + $query = new InvoiceQuery(); - $query->setCustomers([new Customer('foo'), $customer]); + $query->setCustomers([$customer, $customer]); $query->setTemplate($template); self::assertNull($query->getBegin()); self::assertNull($query->getEnd()); @@ -291,7 +304,7 @@ class ServiceInvoiceTest extends TestCase self::assertEquals('de', $template->getLanguage()); $query = new InvoiceQuery(); - $query->setCustomers([$customer3, new Customer('tröööt'), $customer1, $customer3]); + $query->setCustomers([$customer3, $this->getCustomer('tröööt', 1), $customer1, $customer3]); $query->setTemplate($template); self::assertNull($query->getBegin()); self::assertNull($query->getEnd()); diff --git a/tests/Ldap/LdapManagerTest.php b/tests/Ldap/LdapManagerTest.php index 5700e1fa6..f10418b29 100644 --- a/tests/Ldap/LdapManagerTest.php +++ b/tests/Ldap/LdapManagerTest.php @@ -582,52 +582,6 @@ class LdapManagerTest extends TestCase $user = $sut->hydrate($ldapEntry); } - #[Group('legacy')] - public function testHydrateWithDepercatedSetter(): void - { - $ldapConfig = [ - 'connection' => [ - 'host' => '1.1.1.1' - ], - 'user' => [ - 'usernameAttribute' => 'foo', - 'attributes' => [ - ['ldap_attr' => 'uid', 'user_method' => 'setUsername'], // use setUsername here for BC reasons! - ['ldap_attr' => 'foo', 'user_method' => 'setAlias'], - ['ldap_attr' => 'bar', 'user_method' => 'setTitle'], - ['ldap_attr' => 'roles', 'user_method' => 'setRoles'], - ['ldap_attr' => 'xxxxxxxx', 'user_method' => 'setAvatar'], - ['ldap_attr' => 'blubXX', 'user_method' => 'setAvatar'], - ] - ], - 'role' => [], - ]; - $systemConfig = SystemConfigurationFactory::create(new TestConfigLoader([]), ['ldap' => $ldapConfig]); - $config = new LdapConfiguration($systemConfig); - - $ldapEntry = [ - 'uid' => ['Karl-Heinz'], - 'blub' => ['dfsdfsdf'], - 'foo' => ['count' => 1, 0 => 'bar'], - 'bar' => ['foo'], - 'roles' => ['count' => 2, 0 => 'ROLE_TEAMLEAD', 1 => 'ROLE_ADMIN'], - 'xxxxxxxx' => ['https://www.example.com'], - 'blub1' => ['dfsdfsdf'], - 'dn' => 'blub', - ]; - - $sut = new LdapManager($this->createMock(LdapDriver::class), $config, (new RoleServiceFactory($this))->create([])); - $user = $sut->hydrate($ldapEntry); - - self::assertInstanceOf(User::class, $user); - self::assertEquals('Karl-Heinz', $user->getUserIdentifier()); - self::assertEquals('bar', $user->getAlias()); - self::assertEquals('foo', $user->getTitle()); - self::assertEquals(['ROLE_TEAMLEAD', 'ROLE_ADMIN', 'ROLE_USER'], $user->getRoles()); - self::assertEquals('https://www.example.com', $user->getAvatar()); - self::assertEquals('Karl-Heinz', $user->getEmail()); - } - public function testHydrateUser(): void { $ldapConfig = [ diff --git a/tests/Mocks/ActivityTestMetaFieldSubscriberMock.php b/tests/Mocks/ActivityTestMetaFieldSubscriberMock.php index b9f790ec7..f1d6fd3ad 100644 --- a/tests/Mocks/ActivityTestMetaFieldSubscriberMock.php +++ b/tests/Mocks/ActivityTestMetaFieldSubscriberMock.php @@ -30,7 +30,7 @@ class ActivityTestMetaFieldSubscriberMock implements EventSubscriberInterface $definition = (new ActivityMeta()) ->setName('metatestmock') ->setType(TextType::class) - ->addConstraint(new Length(['max' => 200])) + ->addConstraint(new Length(max: 200)) ->setIsVisible(true); $event->getEntity()->setMetaField($definition); diff --git a/tests/Mocks/CustomerTestMetaFieldSubscriberMock.php b/tests/Mocks/CustomerTestMetaFieldSubscriberMock.php index 848b42b00..cc0c96a3c 100644 --- a/tests/Mocks/CustomerTestMetaFieldSubscriberMock.php +++ b/tests/Mocks/CustomerTestMetaFieldSubscriberMock.php @@ -30,7 +30,7 @@ class CustomerTestMetaFieldSubscriberMock implements EventSubscriberInterface $definition = (new CustomerMeta()) ->setName('metatestmock') ->setType(TextType::class) - ->addConstraint(new Length(['max' => 200])) + ->addConstraint(new Length(max: 200)) ->setIsVisible(true); $event->getEntity()->setMetaField($definition); diff --git a/tests/Mocks/PrepareUserEventSubscriberMock.php b/tests/Mocks/PrepareUserEventSubscriberMock.php index 5295ffceb..7a602c784 100644 --- a/tests/Mocks/PrepareUserEventSubscriberMock.php +++ b/tests/Mocks/PrepareUserEventSubscriberMock.php @@ -29,7 +29,7 @@ class PrepareUserEventSubscriberMock implements EventSubscriberInterface { $definition = (new UserPreference('metatestmock')) ->setType(TextType::class) - ->addConstraint(new Length(['max' => 200])) + ->addConstraint(new Length(max: 200)) ->setEnabled(true); $event->getUser()->addPreference($definition); diff --git a/tests/Mocks/ProjectTestMetaFieldSubscriberMock.php b/tests/Mocks/ProjectTestMetaFieldSubscriberMock.php index e55f232b6..85489801b 100644 --- a/tests/Mocks/ProjectTestMetaFieldSubscriberMock.php +++ b/tests/Mocks/ProjectTestMetaFieldSubscriberMock.php @@ -30,7 +30,7 @@ class ProjectTestMetaFieldSubscriberMock implements EventSubscriberInterface $definition = (new ProjectMeta()) ->setName('metatestmock') ->setType(TextType::class) - ->addConstraint(new Length(['max' => 200])) + ->addConstraint(new Length(max: 200)) ->setIsVisible(true); $event->getEntity()->setMetaField($definition); diff --git a/tests/Mocks/TimesheetTestMetaFieldSubscriberMock.php b/tests/Mocks/TimesheetTestMetaFieldSubscriberMock.php index 761563977..4cd1023a1 100644 --- a/tests/Mocks/TimesheetTestMetaFieldSubscriberMock.php +++ b/tests/Mocks/TimesheetTestMetaFieldSubscriberMock.php @@ -30,7 +30,7 @@ class TimesheetTestMetaFieldSubscriberMock implements EventSubscriberInterface $definition = (new TimesheetMeta()) ->setName('metatestmock') ->setType(TextType::class) - ->addConstraint(new Length(['max' => 200])) + ->addConstraint(new Length(max: 200)) ->setIsVisible(true); $event->getEntity()->setMetaField($definition); diff --git a/tests/Project/ProjectServiceTest.php b/tests/Project/ProjectServiceTest.php index a83fa4f18..fdf6b3342 100644 --- a/tests/Project/ProjectServiceTest.php +++ b/tests/Project/ProjectServiceTest.php @@ -182,8 +182,10 @@ class ProjectServiceTest extends TestCase ] ]); + $customer = new Customer('foo'); + $customer->setTimezone('UTC'); $sut = $this->getSut(null, null, $configuration); - $project = $sut->createNewProject(); + $project = $sut->createNewProject($customer); self::assertEquals((string) $expected, $project->getNumber()); } @@ -193,7 +195,7 @@ class ProjectServiceTest extends TestCase */ public static function getTestData(): array { - $dateTime = new \DateTime(); + $dateTime = new \DateTime('now', new \DateTimeZone('UTC')); $yearLong = (int) $dateTime->format('Y'); $yearShort = (int) $dateTime->format('y'); diff --git a/tests/Repository/Loader/AbstractLoaderTestCase.php b/tests/Repository/Loader/AbstractLoaderTestCase.php index 90179956b..2b20f0a49 100644 --- a/tests/Repository/Loader/AbstractLoaderTestCase.php +++ b/tests/Repository/Loader/AbstractLoaderTestCase.php @@ -9,8 +9,8 @@ namespace App\Tests\Repository\Loader; -use Doctrine\ORM\AbstractQuery; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\Query; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\QueryBuilder; use PHPUnit\Framework\TestCase; @@ -22,7 +22,7 @@ abstract class AbstractLoaderTestCase extends TestCase $em = $this->createMock(EntityManager::class); $qb = $this->createMock(QueryBuilder::class); - $query = $this->createMock(AbstractQuery::class); + $query = $this->createMock(Query::class); $expr = $this->createMock(Expr::class); if ($resultMock !== null) { @@ -30,7 +30,7 @@ abstract class AbstractLoaderTestCase extends TestCase } $expr->expects($this->any())->method('isNotNull')->willReturn(''); - $expr->expects($this->any())->method('in')->willReturn(''); + $expr->expects($this->any())->method('in')->willReturn(new Expr\Func('', [])); $qb->expects($this->any())->method('andWhere')->willReturnSelf(); $qb->expects($this->any())->method('from')->willReturnSelf(); diff --git a/tests/Repository/Query/AbstractBaseFormTypeQueryTestCase.php b/tests/Repository/Query/AbstractBaseFormTypeQueryTestCase.php index 2c45bae7f..693002344 100644 --- a/tests/Repository/Query/AbstractBaseFormTypeQueryTestCase.php +++ b/tests/Repository/Query/AbstractBaseFormTypeQueryTestCase.php @@ -41,20 +41,25 @@ abstract class AbstractBaseFormTypeQueryTestCase extends TestCase public function assertTeams(BaseFormTypeQuery $sut): void { + $reflectionTeam = new \ReflectionClass(Team::class); + $teamIdProperty = $reflectionTeam->getProperty('id'); + + $team1 = new Team('foo'); + $teamIdProperty->setValue($team1, 1); + $team2 = new Team('foo'); + $teamIdProperty->setValue($team2, 2); + self::assertEmpty($sut->getTeams()); - self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam(new Team('foo'))); + self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam($team1)); self::assertCount(1, $sut->getTeams()); - $team = new Team('foo'); - self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam($team)); - self::assertCount(1, $sut->getTeams()); - self::assertSame($team, $sut->getTeams()[0]); + self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam($team2)); + self::assertCount(2, $sut->getTeams()); + self::assertSame($team1, $sut->getTeams()[0]); $sut->setTeams([]); self::assertEmpty($sut->getTeams()); - $sut->setTeams([new Team('foo'), new Team('foo')]); - self::assertCount(2, $sut->getTeams()); } public function assertActivity(BaseFormTypeQuery $sut): void diff --git a/tests/Repository/Query/BaseQueryTest.php b/tests/Repository/Query/BaseQueryTest.php index 7a6a89125..cc03177f4 100644 --- a/tests/Repository/Query/BaseQueryTest.php +++ b/tests/Repository/Query/BaseQueryTest.php @@ -96,9 +96,15 @@ class BaseQueryTest extends TestCase protected function assertTeams(BaseQuery $sut): void { + $reflectionTeam = new \ReflectionClass(Team::class); + $teamIdProperty = $reflectionTeam->getProperty('id'); + + $team = new Team('foo'); + $teamIdProperty->setValue($team, 1); + self::assertEmpty($sut->getTeams()); - self::assertInstanceOf(BaseQuery::class, $sut->addTeam(new Team('foo'))); + self::assertInstanceOf(BaseQuery::class, $sut->addTeam($team)); self::assertEquals(1, \count($sut->getTeams())); $sut->setTeams(null); @@ -106,7 +112,9 @@ class BaseQueryTest extends TestCase $sut->setTeams([]); self::assertEmpty($sut->getTeams()); - $team = new Team('foo'); + $team = new Team('foo2'); + $teamIdProperty->setValue($team, 2); + self::assertInstanceOf(BaseQuery::class, $sut->setTeams([$team])); self::assertCount(1, $sut->getTeams()); self::assertSame($team, $sut->getTeams()[0]); diff --git a/tests/Repository/Search/SearchHelperTest.php b/tests/Repository/Search/SearchHelperTest.php index 33f974c9a..eca7d09c1 100644 --- a/tests/Repository/Search/SearchHelperTest.php +++ b/tests/Repository/Search/SearchHelperTest.php @@ -15,6 +15,8 @@ use App\Repository\RepositoryException; use App\Repository\Search\SearchConfiguration; use App\Repository\Search\SearchHelper; use App\Utils\SearchTerm; +use Doctrine\Common\Collections\ArrayCollection; +use Doctrine\DBAL\ParameterType; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr\Andx; @@ -148,39 +150,39 @@ class SearchHelperTest extends TestCase self::assertEquals('LIKE', $orParts[1]->getOperator()); self::assertEquals(':searchTerm3', $orParts[1]->getRightExpr()); - /** @var array $parameters */ + /** @var ArrayCollection $parameters */ $parameters = $qb->getParameters(); self::assertCount(6, $parameters); self::assertInstanceOf(Parameter::class, $parameters[0]); self::assertEquals('metaValue0', $parameters[0]->getName()); self::assertEquals('%value%', $parameters[0]->getValue()); - self::assertEquals(2, $parameters[0]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[0]->getType()); self::assertInstanceOf(Parameter::class, $parameters[1]); self::assertEquals('metaName0', $parameters[1]->getName()); self::assertEquals('metaField', $parameters[1]->getValue()); - self::assertEquals(2, $parameters[1]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[1]->getType()); self::assertInstanceOf(Parameter::class, $parameters[2]); self::assertEquals('searchTerm0', $parameters[2]->getName()); self::assertEquals('%foo%', $parameters[2]->getValue()); - self::assertEquals(2, $parameters[2]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[2]->getType()); self::assertInstanceOf(Parameter::class, $parameters[3]); self::assertEquals('searchTerm1', $parameters[3]->getName()); self::assertEquals('%foo%', $parameters[3]->getValue()); - self::assertEquals(2, $parameters[3]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[3]->getType()); self::assertInstanceOf(Parameter::class, $parameters[4]); self::assertEquals('searchTerm2', $parameters[4]->getName()); self::assertEquals('%test%', $parameters[4]->getValue()); - self::assertEquals(2, $parameters[4]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[4]->getType()); self::assertInstanceOf(Parameter::class, $parameters[5]); self::assertEquals('searchTerm3', $parameters[5]->getName()); self::assertEquals('%test%', $parameters[5]->getValue()); - self::assertEquals(2, $parameters[5]->getType()); + self::assertEquals(ParameterType::STRING, $parameters[5]->getType()); } public function testSearchTermWithExcludedFieldAddsExclusionCondition(): void diff --git a/tests/Repository/TimesheetRepositoryTest.php b/tests/Repository/TimesheetRepositoryTest.php index 98a0c85f0..9cff9e5ae 100644 --- a/tests/Repository/TimesheetRepositoryTest.php +++ b/tests/Repository/TimesheetRepositoryTest.php @@ -40,13 +40,6 @@ class TimesheetRepositoryTest extends AbstractRepositoryTestCase self::assertFalse($query->hasQueryHint(TimesheetQueryHint::CUSTOMER_META_FIELDS)); self::assertFalse($query->hasQueryHint(TimesheetQueryHint::PROJECT_META_FIELDS)); self::assertFalse($query->hasQueryHint(TimesheetQueryHint::ACTIVITY_META_FIELDS)); - - $result = $repository->getTimesheetsForQuery($query, true); - - self::assertTrue($query->hasQueryHint(TimesheetQueryHint::CUSTOMER_META_FIELDS)); - self::assertTrue($query->hasQueryHint(TimesheetQueryHint::PROJECT_META_FIELDS)); - self::assertTrue($query->hasQueryHint(TimesheetQueryHint::ACTIVITY_META_FIELDS)); - self::assertIsArray($result); } public function testSave(): void @@ -108,9 +101,15 @@ class TimesheetRepositoryTest extends AbstractRepositoryTestCase $repository->save($timesheet); self::assertNotNull($timesheet->getId()); self::assertEquals(2, $timesheet->getTags()->count()); - self::assertEquals('Travel', $timesheet->getTags()->get(0)->getName()); - self::assertNotNull($timesheet->getTags()->get(0)->getId()); - self::assertEquals('Picture', $timesheet->getTags()->get(1)->getName()); - self::assertNotNull($timesheet->getTags()->get(1)->getId()); + + $tag = $timesheet->getTags()->get(0); + self::assertInstanceOf(Tag::class, $tag); + self::assertEquals('Travel', $tag->getName()); + self::assertNotNull($tag->getId()); + + $tag = $timesheet->getTags()->get(1); + self::assertInstanceOf(Tag::class, $tag); + self::assertEquals('Picture', $tag->getName()); + self::assertNotNull($tag->getId()); } } diff --git a/tests/Saml/SamlProviderTest.php b/tests/Saml/SamlProviderTest.php index 5955c60cb..c5565a6e6 100644 --- a/tests/Saml/SamlProviderTest.php +++ b/tests/Saml/SamlProviderTest.php @@ -25,7 +25,7 @@ use Symfony\Component\Security\Core\User\UserProviderInterface; #[CoversClass(SamlProvider::class)] class SamlProviderTest extends TestCase { - protected function getSamlProvider(array $mapping = null, ?User $user = null): SamlProvider + protected function getSamlProvider(?array $mapping = null, ?User $user = null): SamlProvider { if (null === $mapping) { $mapping = [ diff --git a/tests/Timesheet/DateTimeFactoryTest.php b/tests/Timesheet/DateTimeFactoryTest.php index e75e89206..e28cdaf66 100644 --- a/tests/Timesheet/DateTimeFactoryTest.php +++ b/tests/Timesheet/DateTimeFactoryTest.php @@ -77,6 +77,17 @@ class DateTimeFactoryTest extends TestCase public function testGetEndOfMonth(): void { + $expected = new DateTime('2024-08-13', new DateTimeZone(self::TEST_TIMEZONE)); + $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); + $dateTime = $sut->getEndOfMonth($expected); + self::assertEquals(23, $dateTime->format('H')); + self::assertEquals(59, $dateTime->format('i')); + self::assertEquals(59, $dateTime->format('s')); + self::assertEquals('31', $dateTime->format('d')); + self::assertEquals('08', $dateTime->format('m')); + self::assertEquals('2024', $dateTime->format('Y')); + self::assertEquals(self::TEST_TIMEZONE, $dateTime->getTimezone()->getName()); + $expected = new DateTime('last day of this month', new DateTimeZone(self::TEST_TIMEZONE)); $sut = $this->createDateTimeFactory(self::TEST_TIMEZONE); $dateTime = $sut->getEndOfMonth(); diff --git a/tests/Timesheet/TimesheetServiceTest.php b/tests/Timesheet/TimesheetServiceTest.php index 0c74d8d28..649549fc0 100644 --- a/tests/Timesheet/TimesheetServiceTest.php +++ b/tests/Timesheet/TimesheetServiceTest.php @@ -23,7 +23,6 @@ use App\Timesheet\TimesheetService; use App\Timesheet\TrackingModeService; use App\Validator\ValidationFailedException; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; @@ -65,20 +64,6 @@ class TimesheetServiceTest extends TestCase return $service; } - #[Group('legacy')] - public function testCannotSavePersistedTimesheetAsNew(): void - { - $timesheet = $this->createMock(Timesheet::class); - $timesheet->expects($this->once())->method('getId')->willReturn(1); - - $sut = $this->getSut(); - - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Cannot create timesheet, already persisted'); - - $sut->saveNewTimesheet($timesheet); // @phpstan-ignore method.deprecated - } - public function testCannotStartTimesheet(): void { $authorizationChecker = $this->createMock(AuthorizationCheckerInterface::class); @@ -161,28 +146,6 @@ class TimesheetServiceTest extends TestCase self::assertEquals('Europe/Paris', $timesheet->getTimezone()); } - #[Group('legacy')] - public function testUpdateTimesheetFixesTimezone(): void - { - $user = new User(); - $user->setTimezone('Europe/Paris'); - - $begin = new \DateTime('now', new \DateTimeZone('Africa/Casablanca')); - $timesheet = new Timesheet(); - - $timesheet->setBegin($begin); - self::assertEquals('Africa/Casablanca', $timesheet->getTimezone()); - - $timesheet->setUser($user); - self::assertEquals('Africa/Casablanca', $timesheet->getTimezone()); - - $sut = $this->getSut(); - - $sut->updateTimesheet($timesheet); // @phpstan-ignore method.deprecated - - self::assertEquals('Europe/Paris', $timesheet->getTimezone()); - } - public function testCannotRestartedPersistedTimesheet(): void { $timesheet = $this->createMock(Timesheet::class); diff --git a/tests/Timesheet/UtilTest.php b/tests/Timesheet/UtilTest.php deleted file mode 100644 index 1e65cebe5..000000000 --- a/tests/Timesheet/UtilTest.php +++ /dev/null @@ -1,112 +0,0 @@ ->|\Generator - */ - public static function getRateCalculationData() - { - yield [0.00, 0, 0.00]; - yield [10.00, 7260, 20.2]; - yield [1.00, 3600, 1.00]; - yield [1.00, 100, 0.03]; - yield [1.00, 900, 0.25]; - yield [1.00, 1800, 0.5]; - yield [10000.00, 60, 200.00]; - yield [736.00, 123, 22.08]; - yield [7360.00, 1234, 2502.4]; - yield [7360.34, 1234, 2502.52]; - yield [7360.01, 1234, 2502.4]; - yield [7360.99, 1234, 2502.74]; - } - - #[Group('legacy')] - public function testCalculateRateWithRounding(): void - { - $total = 0.00; - $seconds = 0; - $repeat = 130; - - $inputs = [ - [900, 28.69, 0], - [1600, 50.49, 0], - [4200, 134.26, 0], - [8763, 278.84, 0], - [3300, 105.57, 0], - [600, 19.51, 0], - [1300, 41.31, 0], - [1837, 58.52, 0], - [4217, 134.26, 0], - [5400, 172.13, 0], - [3283, 104.42, 0], - [600, 19.51, 0], - ]; - - $totalExpected = 0.00; - - for ($a = 0; $a < $repeat; $a++) { - foreach ($inputs as $row) { - [$duration, $rate] = $row; - $seconds += $duration; - $totalExpected += $rate; - $tmp = Util::calculateRate(114.75, $duration); - self::assertEquals($rate, $tmp); - $total += $tmp; - } - } - - self::assertEquals(36000 * $repeat, $seconds); - self::assertEquals($totalExpected, $total); - self::assertEqualsWithDelta(1147.51 * $repeat, $total, 0.00001); - self::assertEqualsWithDelta(149176.3, $total, 0.00001); - } - - #[Group('legacy')] - public function testDecimalDuration(): void - { - $inputs = [ - [900, 900], - [1600, 1584], - [4200, 4212], - [8763, 8748], - [3300, 3312], - [600, 612], - [1300, 1296], - [1837, 1836], - [4217, 4212], - [5400, 5400], - [3283, 3276], - [600, 612], - [7200, 7200], - ]; - - foreach ($inputs as $row) { - self::assertEquals($row[1], Util::decimalizeDuration($row[0])); - } - } -} diff --git a/tests/Twig/ContextTest.php b/tests/Twig/ContextTest.php index 6a497acce..79c7f2c06 100644 --- a/tests/Twig/ContextTest.php +++ b/tests/Twig/ContextTest.php @@ -10,8 +10,6 @@ namespace App\Tests\Twig; use App\Configuration\SystemConfiguration; -use App\Tests\Configuration\TestConfigLoader; -use App\Tests\Mocks\SystemConfigurationFactory; use App\Twig\Context; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -24,9 +22,6 @@ class ContextTest extends TestCase { protected function getSut(array $settings, array $headers = []): Context { - $loader = new TestConfigLoader([]); - $config = SystemConfigurationFactory::create($loader, ['theme' => $settings]); - $stack = new RequestStack(); $request = new Request(); foreach ($headers as $name => $value) { @@ -34,13 +29,10 @@ class ContextTest extends TestCase } $stack->push($request); - return new Context($config, $stack); + return new Context($stack); } - /** - * @return array - */ - protected function getDefaultSettings() + protected function getDefaultSettings(): array { return [ 'show_about' => true, @@ -50,12 +42,6 @@ class ContextTest extends TestCase 'grid_color' => 'rgba(0,0,0,.05)', 'height' => '200' ], - 'branding' => [ - 'logo' => 'Logooooo', - 'mini' => 'Mini2', - 'company' => 'Super Kimai', - 'title' => null, - ], ]; } diff --git a/tests/Twig/ExtensionsTest.php b/tests/Twig/ExtensionsTest.php index 1195c0b24..ff392a667 100644 --- a/tests/Twig/ExtensionsTest.php +++ b/tests/Twig/ExtensionsTest.php @@ -43,7 +43,7 @@ class ExtensionsTest extends TestCase public function testGetFilters(): void { - $filters = ['report_date', 'docu_link', 'multiline_indent', 'color', 'font_contrast', 'default_color', 'nl2str']; + $filters = ['month_picker', 'report_date', 'docu_link', 'multiline_indent', 'color', 'font_contrast', 'default_color', 'nl2str']; $sut = $this->getSut(); $twigFilters = $sut->getFilters(); self::assertCount(\count($filters), $twigFilters); diff --git a/tests/Twig/LocaleFormatExtensionsTest.php b/tests/Twig/LocaleFormatExtensionsTest.php index d31fe949f..24f5ca452 100644 --- a/tests/Twig/LocaleFormatExtensionsTest.php +++ b/tests/Twig/LocaleFormatExtensionsTest.php @@ -48,7 +48,7 @@ class LocaleFormatExtensionsTest extends TestCase } /** - * @param array $languageSettings + * @param array $languageSettings */ private function getSut(string $locale, array $languageSettings): LocaleFormatExtensions { diff --git a/tests/Twig/PaginationExtensionTest.php b/tests/Twig/PaginationExtensionTest.php index deb48802d..85405f100 100644 --- a/tests/Twig/PaginationExtensionTest.php +++ b/tests/Twig/PaginationExtensionTest.php @@ -63,9 +63,9 @@ class PaginationExtensionTest extends TestCase $sut = $this->getSut(); $values = array_fill(0, 151, 'blub'); - $pagerfanta = new Pagination(new ArrayAdapter($values)); - $pagerfanta->setMaxPerPage(10); - $result = $sut->renderPagination($pagerfanta, [ + $pagination = new Pagination(new ArrayAdapter($values)); + $pagination->setMaxPerPage(10); + $result = $sut->renderPagination($pagination, [ 'css_container_class' => 'pagination pagination-sm inline', 'routeName' => 'project_activities', 'routeParams' => ['id' => 137] @@ -97,9 +97,9 @@ class PaginationExtensionTest extends TestCase $sut = $this->getSut(); $values = array_fill(0, 151, 'blub'); - $pagerfanta = new Pagination(new ArrayAdapter($values)); - $pagerfanta->setMaxPerPage(10); - $result = $sut->renderPagination($pagerfanta, [ + $pagination = new Pagination(new ArrayAdapter($values)); + $pagination->setMaxPerPage(10); + $result = $sut->renderPagination($pagination, [ 'css_container_class' => 'pagination pagination-sm inline', 'routeName' => 'project_activities', 'routeParams' => ['id' => 137] @@ -112,8 +112,8 @@ class PaginationExtensionTest extends TestCase $sut = $this->getSut(); $values = array_fill(0, 151, 'blub'); - $pagerfanta = new Pagination(new ArrayAdapter($values)); - $result = $sut->renderPagination($pagerfanta, [ + $pagination = new Pagination(new ArrayAdapter($values)); + $result = $sut->renderPagination($pagination, [ 'css_container_class' => 'pagination pagination-sm inline', 'routeName' => 'project_activities', 'routeParams' => ['id' => 137] @@ -135,8 +135,8 @@ class PaginationExtensionTest extends TestCase $sut = $this->getSut(); $values = array_fill(0, 151, 'blub'); - $pagerfanta = new Pagination(new ArrayAdapter($values)); - $result = $sut->renderPagination($pagerfanta, [ + $pagination = new Pagination(new ArrayAdapter($values)); + $result = $sut->renderPagination($pagination, [ 'css_container_class' => 'pagination pagination-sm inline', 'routeParams' => ['id' => 137] ]); diff --git a/tests/Twig/Runtime/ThemeEventExtensionTest.php b/tests/Twig/Runtime/ThemeEventExtensionTest.php index 9383edb83..da2a5f2be 100644 --- a/tests/Twig/Runtime/ThemeEventExtensionTest.php +++ b/tests/Twig/Runtime/ThemeEventExtensionTest.php @@ -12,7 +12,6 @@ namespace App\Tests\Twig\Runtime; use App\Entity\User; use App\Event\ThemeEvent; use App\Tests\Configuration\TestConfigLoader; -use App\Tests\Event\ThemeJavascriptTranslationsEventTest; use App\Tests\Mocks\SystemConfigurationFactory; use App\Twig\Runtime\ThemeExtension; use PHPUnit\Framework\Attributes\CoversClass; @@ -96,9 +95,9 @@ class ThemeEventExtensionTest extends TestCase public function testJavascriptTranslations(): void { - $sut = $this->getSut(); + $sut = $this->getSut(false); $values = $sut->getJavascriptTranslations(); - self::assertCount(ThemeJavascriptTranslationsEventTest::COUNTER, $values); + self::assertCount(17, $values); } public static function getProgressbarColors() diff --git a/tests/Twig/SecurityPolicy/AbstractPolicyTestCase.php b/tests/Twig/SecurityPolicy/AbstractPolicyTestCase.php new file mode 100644 index 000000000..9b307a226 --- /dev/null +++ b/tests/Twig/SecurityPolicy/AbstractPolicyTestCase.php @@ -0,0 +1,91 @@ +createPolicy(); + $sut->checkSecurity([], [], []); + $this->expectNotToPerformAssertions(); + } + + public function testCheckPropertyAllowed(): void + { + $sut = $this->createPolicy(); + $sut->checkPropertyAllowed(new \stdClass(), 'foo'); + $this->expectNotToPerformAssertions(); + } + + #[DataProvider('getCheckMethodAllowedData')] + public function testCheckMethodAllowed(object $obj, string $method, ?string $expectedExceptionMessage = null): void + { + $sut = $this->createPolicy(); + + if ($expectedExceptionMessage !== null) { + $this->expectException(SecurityNotAllowedMethodError::class); + $this->expectExceptionMessage($expectedExceptionMessage); + } + + $sut->checkMethodAllowed($obj, $method); + + if ($expectedExceptionMessage === null) { + $this->expectNotToPerformAssertions(); + } + } + + public static function getCheckMethodAllowedData(): array + { + return [ + [new ServerBag(), 'get', 'Tried to access server environment'], + [self::createStub(SessionInterface::class), 'getId', 'Tried to access session'], + [new \stdClass(), 'foo', 'Tried to access non-read method'], + [new \stdClass(), 'setFoo', 'Tried to access non-read method'], + [new \stdClass(), 'getFoo'], + [new \stdClass(), 'hasFoo'], + [new \stdClass(), 'isFoo'], + [new UnicodeString(), '__toString'], + // Request + [new Request(), 'get', null], + [new Request(), 'isXmlHttpRequest', 'Tried to call setter() of app variable'], + [new Request(), 'hasSession', 'Tried to call setter() of app variable'], + // PdfContext + [new PdfContext(), 'setOption'], + [new PdfContext(), 'getOption', 'Tried to access forbidden method on PdfContext'], + // AppVariable + [new AppVariable(), 'getRequest'], + [new AppVariable(), 'getUser'], + [new AppVariable(), 'getLocale'], + [new AppVariable(), 'getCharset', 'Tried to access forbidden app variable method'], + // User + [new User(), 'getUsername'], + [new User(), 'getPassword', 'Tried to access user secrets'], + [new User(), 'getTotpSecret', 'Tried to access user secrets'], + [new User(), 'getPlainPassword', 'Tried to access user secrets'], + [new User(), 'getConfirmationToken', 'Tried to access user secrets'], + [new User(), 'getTotpAuthenticationConfiguration', 'Tried to access user secrets'], + ]; + } +} diff --git a/tests/Twig/SecurityPolicy/ChainPolicyTest.php b/tests/Twig/SecurityPolicy/ChainPolicyTest.php new file mode 100644 index 000000000..8b4638843 --- /dev/null +++ b/tests/Twig/SecurityPolicy/ChainPolicyTest.php @@ -0,0 +1,66 @@ +createMock(SecurityPolicyInterface::class); + $policy1->expects(self::once())->method('checkSecurity')->with(['tag'], ['filter'], ['function']); + + $policy2 = $this->createMock(SecurityPolicyInterface::class); + $policy2->expects(self::once())->method('checkSecurity')->with(['tag'], ['filter'], ['function']); + + $sut = new ChainPolicy(); + $sut->addPolicy($policy1); + $sut->addPolicy($policy2); + + $sut->checkSecurity(['tag'], ['filter'], ['function']); + } + + public function testCheckMethodAllowed(): void + { + $obj = new \stdClass(); + $policy1 = $this->createMock(SecurityPolicyInterface::class); + $policy1->expects(self::once())->method('checkMethodAllowed')->with($obj, 'method'); + + $policy2 = $this->createMock(SecurityPolicyInterface::class); + $policy2->expects(self::once())->method('checkMethodAllowed')->with($obj, 'method'); + + $sut = new ChainPolicy(); + $sut->addPolicy($policy1); + $sut->addPolicy($policy2); + + $sut->checkMethodAllowed($obj, 'method'); + } + + public function testCheckPropertyAllowed(): void + { + $obj = new \stdClass(); + $policy1 = $this->createMock(SecurityPolicyInterface::class); + $policy1->expects(self::once())->method('checkPropertyAllowed')->with($obj, 'property'); + + $policy2 = $this->createMock(SecurityPolicyInterface::class); + $policy2->expects(self::once())->method('checkPropertyAllowed')->with($obj, 'property'); + + $sut = new ChainPolicy(); + $sut->addPolicy($policy1); + $sut->addPolicy($policy2); + + $sut->checkPropertyAllowed($obj, 'property'); + } +} diff --git a/tests/Twig/SecurityPolicy/DefaultPolicyTest.php b/tests/Twig/SecurityPolicy/DefaultPolicyTest.php new file mode 100644 index 000000000..21d970819 --- /dev/null +++ b/tests/Twig/SecurityPolicy/DefaultPolicyTest.php @@ -0,0 +1,23 @@ +createPolicy(); + $sut->checkSecurity([], [], []); + $this->expectNotToPerformAssertions(); + } + + #[DataProvider('getCheckMethodAllowedData')] + public function testCheckMethodAllowed(object $obj, string $method, ?string $expectedExceptionMessage = null): void + { + $sut = $this->createPolicy(); + + if ($expectedExceptionMessage !== null) { + $this->expectException(SecurityNotAllowedMethodError::class); + $this->expectExceptionMessage($expectedExceptionMessage); + } + + $sut->checkMethodAllowed($obj, $method); + + if ($expectedExceptionMessage === null) { + $this->expectNotToPerformAssertions(); + } + } + + public static function getCheckMethodAllowedData(): array + { + return [ + [new ServerBag(), 'get', 'Tried to access server environment'], + [self::createStub(SessionInterface::class), 'getId', 'Tried to access session'], + [new \stdClass(), 'foo', 'Tried to access non-read method'], + [new \stdClass(), 'setFoo', 'Tried to access non-read method'], + [new \stdClass(), 'getFoo'], + [new \stdClass(), 'hasFoo'], + [new \stdClass(), 'isFoo'], + [new UnicodeString(), '__toString'], + // Request + [new Request(), 'get', null], + [new Request(), 'isXmlHttpRequest', 'Tried to call setter() of app variable'], + [new Request(), 'hasSession', 'Tried to call setter() of app variable'], + // PdfContext + [new PdfContext(), 'setOption'], + [new PdfContext(), 'getOption', 'Tried to access forbidden method on PdfContext'], + // AppVariable + [new AppVariable(), 'getRequest'], + [new AppVariable(), 'getUser'], + [new AppVariable(), 'getLocale'], + [new AppVariable(), 'getCharset', 'Tried to access forbidden app variable method'], + // User + [new User(), 'getUsername'], + [new User(), 'getPassword', 'Tried to access user secrets'], + [new User(), 'getTotpSecret', 'Tried to access user secrets'], + [new User(), 'getPlainPassword', 'Tried to access user secrets'], + [new User(), 'getConfirmationToken', 'Tried to access user secrets'], + [new User(), 'getTotpAuthenticationConfiguration', 'Tried to access user secrets'], + ]; + } +} diff --git a/tests/Utils/PageSetupTest.php b/tests/Utils/PageSetupTest.php index 2fabb0fba..bd23fb69a 100644 --- a/tests/Utils/PageSetupTest.php +++ b/tests/Utils/PageSetupTest.php @@ -12,6 +12,8 @@ namespace App\Tests\Utils; use App\Repository\Query\BaseQuery; use App\Utils\DataTable; use App\Utils\PageSetup; +use App\Utils\Pagination; +use Pagerfanta\Adapter\ArrayAdapter; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\TestCase; @@ -32,7 +34,7 @@ class PageSetupTest extends TestCase public function testSetter(): void { - $dataTable = new DataTable('tadaaaaa', new BaseQuery()); + $dataTable = new DataTable('tadaaaaa', new BaseQuery(), new Pagination(new ArrayAdapter([]))); $sut = new PageSetup('foo-bar'); $sut->setDataTable($dataTable); $sut->setActionName('some-action'); diff --git a/tests/Utils/SearchTermTest.php b/tests/Utils/SearchTermTest.php index a6a167b31..54c338880 100644 --- a/tests/Utils/SearchTermTest.php +++ b/tests/Utils/SearchTermTest.php @@ -11,7 +11,6 @@ namespace App\Tests\Utils; use App\Utils\SearchTerm; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; #[CoversClass(SearchTerm::class)] @@ -20,8 +19,6 @@ class SearchTermTest extends TestCase public function testNormalSearchTerm(): void { $sut = new SearchTerm('foo bar test 1'); - self::assertEquals('foo bar test 1', $sut->getSearchTerm()); - self::assertEmpty($sut->getSearchFields()); self::assertTrue($sut->hasSearchTerm()); self::assertEquals('foo bar test 1', $sut->getOriginalSearch()); self::assertEquals('foo bar test 1', (string) $sut); @@ -44,9 +41,6 @@ class SearchTermTest extends TestCase { $sut = new SearchTerm('foo:bar'); self::assertFalse($sut->hasSearchTerm()); - self::assertEquals('', $sut->getSearchTerm()); - self::assertNotEmpty($sut->getSearchFields()); - self::assertEquals(['foo' => 'bar'], $sut->getSearchFields()); self::assertEquals('foo:bar', $sut->getOriginalSearch()); self::assertCount(1, $sut->getParts()); $expectedParts = [ @@ -61,30 +55,10 @@ class SearchTermTest extends TestCase } } - #[Group('legacy')] - public function testWithMultipleMetaFields(): void - { - $sut = new SearchTerm('foo:bar bar:foo'); - self::assertFalse($sut->hasSearchTerm()); - self::assertEquals('', $sut->getSearchTerm()); - self::assertNotEmpty($sut->getSearchFields()); - self::assertFalse($sut->hasSearchField('test')); // @phpstan-ignore method.deprecated - self::assertTrue($sut->hasSearchField('foo')); // @phpstan-ignore method.deprecated - self::assertTrue($sut->hasSearchField('bar')); // @phpstan-ignore method.deprecated - self::assertEquals('bar', $sut->getSearchField('foo')); // @phpstan-ignore method.deprecated - self::assertEquals('foo', $sut->getSearchField('bar')); // @phpstan-ignore method.deprecated - self::assertEquals(['foo' => 'bar', 'bar' => 'foo'], $sut->getSearchFields()); - self::assertEquals('foo:bar bar:foo', $sut->getOriginalSearch()); - self::assertCount(2, $sut->getParts()); - } - public function testComplexWithMultipleAndDuplicateMetaFields(): void { $sut = new SearchTerm('foo:bar hello bar:!foo world test foo:bar2 wuff'); self::assertTrue($sut->hasSearchTerm()); - self::assertEquals('hello world test wuff', $sut->getSearchTerm()); - self::assertNotEmpty($sut->getSearchFields()); - self::assertEquals(['foo' => 'bar2', 'bar' => 'foo'], $sut->getSearchFields()); self::assertEquals('foo:bar hello bar:!foo world test foo:bar2 wuff', $sut->getOriginalSearch()); self::assertCount(7, $sut->getParts()); $expectedParts = [ @@ -109,9 +83,6 @@ class SearchTermTest extends TestCase { $sut = new SearchTerm('ABC-123: abcd: abcd'); self::assertTrue($sut->hasSearchTerm()); - self::assertEquals('ABC-123: abcd: abcd', $sut->getSearchTerm()); - self::assertEmpty($sut->getSearchFields()); - self::assertEquals([], $sut->getSearchFields()); self::assertEquals('ABC-123: abcd: abcd', $sut->getOriginalSearch()); self::assertCount(3, $sut->getParts()); $expectedParts = [ @@ -129,9 +100,6 @@ class SearchTermTest extends TestCase $sut = new SearchTerm('1 : 1:.'); self::assertTrue($sut->hasSearchTerm()); - self::assertEquals('1 :', $sut->getSearchTerm()); - self::assertNotEmpty($sut->getSearchFields()); - self::assertSame([1 => '.'], $sut->getSearchFields()); // this is weird, should be a string, but PHP seems to think otherwise self::assertEquals('1 : 1:.', $sut->getOriginalSearch()); self::assertCount(3, $sut->getParts()); $expectedParts = [ @@ -152,9 +120,6 @@ class SearchTermTest extends TestCase { $sut = new SearchTerm('ABC-123:"" abcd:"" abcd'); self::assertTrue($sut->hasSearchTerm()); - self::assertEquals('abcd', $sut->getSearchTerm()); - self::assertNotEmpty($sut->getSearchFields()); - self::assertEquals(['ABC-123' => '', 'abcd' => ''], $sut->getSearchFields()); self::assertEquals('ABC-123:"" abcd:"" abcd', $sut->getOriginalSearch()); self::assertCount(3, $sut->getParts()); $expectedParts = [ diff --git a/tests/Validator/Constraints/AbstractConstraintTestCase.php b/tests/Validator/Constraints/AbstractConstraintTestCase.php new file mode 100644 index 000000000..56d2f44c3 --- /dev/null +++ b/tests/Validator/Constraints/AbstractConstraintTestCase.php @@ -0,0 +1,25 @@ +getAttributes(TimesheetConstraint::class); + self::assertCount(1, $attributes); + self::assertEquals(TimesheetConstraint::class, $attributes[0]->getName()); + } +} diff --git a/tests/Validator/Constraints/DurationValidatorTest.php b/tests/Validator/Constraints/DurationValidatorTest.php index 0554a2b8f..c1607bcf2 100644 --- a/tests/Validator/Constraints/DurationValidatorTest.php +++ b/tests/Validator/Constraints/DurationValidatorTest.php @@ -102,9 +102,7 @@ class DurationValidatorTest extends ConstraintValidatorTestCase #[DataProvider('getInvalidData')] public function testValidationError(string $input): void { - $constraint = new Duration([ - 'message' => 'myMessage', - ]); + $constraint = new Duration(message: 'myMessage'); $this->validator->validate($input, $constraint); @@ -119,9 +117,7 @@ class DurationValidatorTest extends ConstraintValidatorTestCase public function testValidationErrorUpperCase(string $input): void { $input = strtoupper($input); - $constraint = new Duration([ - 'message' => 'myMessage', - ]); + $constraint = new Duration(message: 'myMessage'); $this->validator->validate($input, $constraint); diff --git a/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php b/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php index 1464a0d74..ddeb6188a 100644 --- a/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php +++ b/tests/Validator/Constraints/QuickEntryTimesheetValidatorTest.php @@ -34,7 +34,7 @@ class QuickEntryTimesheetValidatorTest extends ConstraintValidatorTestCase protected function createValidator(): ConstraintValidatorInterface { - return new QuickEntryTimesheetValidator([new TimesheetBasic()]); + return new QuickEntryTimesheetValidator([TimesheetBasic::class]); } public function testConstraintIsInvalid(): void diff --git a/tests/Validator/Constraints/RoleNameValidatorTest.php b/tests/Validator/Constraints/RoleNameValidatorTest.php index f3f75f7a5..76e33d9b3 100644 --- a/tests/Validator/Constraints/RoleNameValidatorTest.php +++ b/tests/Validator/Constraints/RoleNameValidatorTest.php @@ -64,7 +64,7 @@ class RoleNameValidatorTest extends ConstraintValidatorTestCase public function testNullIsInvalid(): void { - $this->validator->validate(null, new RoleName(['message' => 'myMessage'])); + $this->validator->validate(null, new RoleName(message: 'myMessage')); $this->buildViolation('myMessage') ->setParameter('{{ value }}', 'null') @@ -99,9 +99,7 @@ class RoleNameValidatorTest extends ConstraintValidatorTestCase #[DataProvider('getInvalidRoleNames')] public function testValidationError(string|int $role): void { - $constraint = new RoleName([ - 'message' => 'myMessage', - ]); + $constraint = new RoleName(message: 'myMessage'); $this->validator->validate($role, $constraint); diff --git a/tests/Validator/Constraints/RoleValidatorTest.php b/tests/Validator/Constraints/RoleValidatorTest.php index 1819ff406..cc498bd2f 100644 --- a/tests/Validator/Constraints/RoleValidatorTest.php +++ b/tests/Validator/Constraints/RoleValidatorTest.php @@ -61,7 +61,7 @@ class RoleValidatorTest extends ConstraintValidatorTestCase public function testNullIsInvalid(): void { - $this->validator->validate(null, new Role(['message' => 'myMessage'])); + $this->validator->validate(null, new Role(message: 'myMessage')); $this->buildViolation('myMessage') ->setParameter('{{ value }}', 'null') @@ -84,9 +84,7 @@ class RoleValidatorTest extends ConstraintValidatorTestCase #[DataProvider('getInvalidRoles')] public function testValidationError(mixed $role): void { - $constraint = new Role([ - 'message' => 'myMessage', - ]); + $constraint = new Role(message: 'myMessage'); $this->validator->validate($role, $constraint); diff --git a/tests/Validator/Constraints/TimesheetValidatorTest.php b/tests/Validator/Constraints/TimesheetAllValidatorTest.php similarity index 67% rename from tests/Validator/Constraints/TimesheetValidatorTest.php rename to tests/Validator/Constraints/TimesheetAllValidatorTest.php index 7b87e169f..335127d27 100644 --- a/tests/Validator/Constraints/TimesheetValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetAllValidatorTest.php @@ -10,28 +10,28 @@ namespace App\Tests\Validator\Constraints; use App\Entity\Timesheet; -use App\Validator\Constraints\Timesheet as TimesheetConstraint; -use App\Validator\Constraints\TimesheetValidator; +use App\Validator\Constraints\TimesheetAll; +use App\Validator\Constraints\TimesheetAllValidator; use PHPUnit\Framework\Attributes\CoversClass; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** - * @extends ConstraintValidatorTestCase + * @extends ConstraintValidatorTestCase */ -#[CoversClass(\App\Validator\Constraints\Timesheet::class)] -#[CoversClass(TimesheetValidator::class)] -class TimesheetValidatorTest extends ConstraintValidatorTestCase +#[CoversClass(TimesheetAll::class)] +#[CoversClass(TimesheetAllValidator::class)] +class TimesheetAllValidatorTest extends ConstraintValidatorTestCase { - protected function createValidator(): TimesheetValidator + protected function createValidator(): TimesheetAllValidator { return $this->createMyValidator(); } - protected function createMyValidator(bool $isGranted = true): TimesheetValidator + protected function createMyValidator(bool $isGranted = true): TimesheetAllValidator { - return new TimesheetValidator([]); + return new TimesheetAllValidator([]); } public function testConstraintIsInvalid(): void @@ -45,6 +45,6 @@ class TimesheetValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetConstraint(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetAll()); } } diff --git a/tests/Validator/Constraints/TimesheetBasicTest.php b/tests/Validator/Constraints/TimesheetBasicTest.php index 0032ba579..8439796bd 100644 --- a/tests/Validator/Constraints/TimesheetBasicTest.php +++ b/tests/Validator/Constraints/TimesheetBasicTest.php @@ -10,15 +10,13 @@ namespace App\Tests\Validator\Constraints; use App\Validator\Constraints\TimesheetBasic; -use App\Validator\Constraints\TimesheetConstraint; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetBasic::class)] -class TimesheetBasicTest extends TestCase +class TimesheetBasicTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetBasic()); + $this->assertTimesheetConstraint(new TimesheetBasic()); } } diff --git a/tests/Validator/Constraints/TimesheetBasicValidatorTest.php b/tests/Validator/Constraints/TimesheetBasicValidatorTest.php index fe3f3c5bc..88e407b53 100644 --- a/tests/Validator/Constraints/TimesheetBasicValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetBasicValidatorTest.php @@ -52,13 +52,13 @@ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetBasic()); } public function testEmptyTimesheet(): void { $timesheet = new Timesheet(); - $this->validator->validate($timesheet, new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetBasic()); $this->buildViolation('You must submit a begin date.') ->atPath('property.path.begin_date') @@ -78,7 +78,7 @@ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $this->validator->validate($timesheet, new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetBasic()); $this ->buildViolation('An activity needs to be selected.') @@ -105,7 +105,7 @@ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase $timesheet->setBegin($begin); $timesheet->setEnd($end); - $this->validator->validate($timesheet, new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetBasic()); $this->buildViolation('End date must not be earlier then start date.') ->atPath('property.path.end_date') @@ -137,7 +137,7 @@ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase ->setProject($project2) ; - $this->validator->validate($timesheet, new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetBasic()); $this->buildViolation('Project mismatch, project specific activity and timesheet project are different.') ->atPath('property.path.project') @@ -187,7 +187,7 @@ class TimesheetBasicValidatorTest extends ConstraintValidatorTestCase $timesheet->setProject($project); $timesheet->setActivity(new Activity()); - $this->validator->validate($timesheet, new TimesheetBasic(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetBasic()); $assertion = null; foreach ($violations as $violation) { diff --git a/tests/Validator/Constraints/TimesheetBudgetUsedTest.php b/tests/Validator/Constraints/TimesheetBudgetUsedTest.php index 663382a43..5cef12d2a 100644 --- a/tests/Validator/Constraints/TimesheetBudgetUsedTest.php +++ b/tests/Validator/Constraints/TimesheetBudgetUsedTest.php @@ -10,15 +10,13 @@ namespace App\Tests\Validator\Constraints; use App\Validator\Constraints\TimesheetBudgetUsed; -use App\Validator\Constraints\TimesheetConstraint; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetBudgetUsed::class)] -class TimesheetBudgetUsedTest extends TestCase +class TimesheetBudgetUsedTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetBudgetUsed()); + $this->assertTimesheetConstraint(new TimesheetBudgetUsed()); } } diff --git a/tests/Validator/Constraints/TimesheetDeactivatedTest.php b/tests/Validator/Constraints/TimesheetDeactivatedTest.php index f2eba5521..8194f833f 100644 --- a/tests/Validator/Constraints/TimesheetDeactivatedTest.php +++ b/tests/Validator/Constraints/TimesheetDeactivatedTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetDeactivated; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetDeactivated::class)] -class TimesheetDeactivatedTest extends TestCase +class TimesheetDeactivatedTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetDeactivated()); + $this->assertTimesheetConstraint(new TimesheetDeactivated()); } } diff --git a/tests/Validator/Constraints/TimesheetDeactivatedValidatorTest.php b/tests/Validator/Constraints/TimesheetDeactivatedValidatorTest.php index f3a12a6b4..cabb657ba 100644 --- a/tests/Validator/Constraints/TimesheetDeactivatedValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetDeactivatedValidatorTest.php @@ -43,7 +43,7 @@ class TimesheetDeactivatedValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetDeactivated(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetDeactivated()); } public function testDisabledValuesDuringStart(): void @@ -65,7 +65,7 @@ class TimesheetDeactivatedValidatorTest extends ConstraintValidatorTestCase ->setProject($project) ; - $this->validator->validate($timesheet, new TimesheetDeactivated(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetDeactivated()); $this->buildViolation(TimesheetDeactivated::getErrorName(TimesheetDeactivated::DISABLED_ACTIVITY_ERROR)) ->atPath('property.path.activity') diff --git a/tests/Validator/Constraints/TimesheetExportedTest.php b/tests/Validator/Constraints/TimesheetExportedTest.php index 39c3e2ade..d4fad3767 100644 --- a/tests/Validator/Constraints/TimesheetExportedTest.php +++ b/tests/Validator/Constraints/TimesheetExportedTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetExported; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetExported::class)] -class TimesheetExportedTest extends TestCase +class TimesheetExportedTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetExported()); + $this->assertTimesheetConstraint(new TimesheetExported()); } } diff --git a/tests/Validator/Constraints/TimesheetExportedValidatorTest.php b/tests/Validator/Constraints/TimesheetExportedValidatorTest.php index 3a15e6bea..93232975a 100644 --- a/tests/Validator/Constraints/TimesheetExportedValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetExportedValidatorTest.php @@ -60,7 +60,7 @@ class TimesheetExportedValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetExported(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetExported()); } public function testTriggersOnMissingPermission(): void diff --git a/tests/Validator/Constraints/TimesheetFutureTimesTest.php b/tests/Validator/Constraints/TimesheetFutureTimesTest.php index 05078858d..4f1f54a78 100644 --- a/tests/Validator/Constraints/TimesheetFutureTimesTest.php +++ b/tests/Validator/Constraints/TimesheetFutureTimesTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetFutureTimes; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetFutureTimes::class)] -class TimesheetFutureTimesTest extends TestCase +class TimesheetFutureTimesTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetFutureTimes()); + $this->assertTimesheetConstraint(new TimesheetFutureTimes()); } } diff --git a/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php b/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php index 7307cfa30..cc9dce262 100644 --- a/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetFutureTimesValidatorTest.php @@ -61,7 +61,7 @@ class TimesheetFutureTimesValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetFutureTimes(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetFutureTimes()); } public function testFutureBeginIsDisallowed(): void @@ -70,7 +70,7 @@ class TimesheetFutureTimesValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $this->validator->validate($timesheet, new TimesheetFutureTimes(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetFutureTimes()); $this->buildViolation('The begin date cannot be in the future.') ->atPath('property.path.begin_date') @@ -87,7 +87,7 @@ class TimesheetFutureTimesValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $this->validator->validate($timesheet, new TimesheetFutureTimes(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetFutureTimes()); self::assertEmpty($this->context->getViolations()); } } diff --git a/tests/Validator/Constraints/TimesheetLockdownTest.php b/tests/Validator/Constraints/TimesheetLockdownTest.php index 2f190a0d0..6291c1412 100644 --- a/tests/Validator/Constraints/TimesheetLockdownTest.php +++ b/tests/Validator/Constraints/TimesheetLockdownTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetLockdown; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetLockdown::class)] -class TimesheetLockdownTest extends TestCase +class TimesheetLockdownTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetLockdown()); + $this->assertTimesheetConstraint(new TimesheetLockdown()); } } diff --git a/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php b/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php index 8318e6ceb..cd0e59128 100644 --- a/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetLockdownValidatorTest.php @@ -24,6 +24,7 @@ use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; /** + * TODO this should use a clock to simulate different "now" for testing the grace period * @extends ConstraintValidatorTestCase */ #[CoversClass(TimesheetLockdown::class)] @@ -77,7 +78,7 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetLockdown(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetLockdown()); } public function testValidatorWithoutNowConstraint(): void @@ -90,7 +91,7 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $constraint = new TimesheetLockdown(['message' => 'myMessage']); + $constraint = new TimesheetLockdown(); $this->validator->validate($timesheet, $constraint); @@ -105,28 +106,12 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase $this->validator = $this->createMyValidator(false, false, 'first day of last month', 'last day of last month', '+10 days'); $this->validator->initialize($this->context); - $constraint = new TimesheetLockdown(['message' => 'myMessage']); + $constraint = new TimesheetLockdown(); $this->validator->validate(new Timesheet(), $constraint); self::assertEmpty($this->context->getViolations()); } - public function testValidatorWithoutNowStringConstraint(): void - { - $this->validator = $this->createMyValidator(false, false, 'first day of last month', 'last day of last month', '+10 days'); - $this->validator->initialize($this->context); - - $begin = new \DateTime('first day of last month'); - $begin->modify('+5 days'); - $timesheet = new Timesheet(); - $timesheet->setBegin($begin); - - $constraint = new TimesheetLockdown(['message' => 'myMessage', 'now' => 'first day of this month']); - - $this->validator->validate($timesheet, $constraint); - self::assertEmpty($this->context->getViolations()); - } - public function testValidatorWithEndBeforeStartPeriod(): void { $this->validator = $this->createMyValidator(false, false, 'first day of this month', 'last day of last month', '+10 days'); @@ -137,14 +122,14 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $constraint = new TimesheetLockdown(['message' => 'myMessage', 'now' => 'first day of this month']); + $constraint = new TimesheetLockdown(); $this->validator->validate($timesheet, $constraint); self::assertEmpty($this->context->getViolations()); } #[DataProvider('getTestData')] - public function testLockdown(bool $allowOverwriteFull, bool $allowOverwriteGrace, string $beginModifier, string $nowModifier, bool $isViolation): void + public function testLockdown(bool $allowOverwriteFull, bool $allowOverwriteGrace, string $beginModifier, bool $isViolation): void { $this->validator = $this->createMyValidator($allowOverwriteFull, $allowOverwriteGrace, 'first day of last month', 'last day of last month', '+10 days'); $this->validator->initialize($this->context); @@ -154,10 +139,7 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $now = new \DateTime('first day of this month'); - $now->modify($nowModifier); - - $constraint = new TimesheetLockdown(['message' => 'myMessage', 'now' => $now]); + $constraint = new TimesheetLockdown(); $this->validator->validate($timesheet, $constraint); @@ -174,20 +156,18 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase public static function getTestData(): iterable { // changing before last dockdown period is not allowed - yield [false, false, '-5 days', '+5 days', true]; + yield [false, false, '-5 days', true]; // changing before last dockdown period is not allowed with grace permission - yield [false, true, '-5 days', '+5 days', true]; + yield [false, true, '-5 days', true]; // changing before last dockdown period is allowed with full permission - yield [true, true, '-5 days', '+5 days', false]; - yield [true, false, '-5 days', '+5 days', false]; - // changing a value in the last lockdown period is allowed during grace period - yield [false, false, '+5 days', '+5 days', false]; - // changing outside grace period is not allowed - yield [false, false, '+5 days', '+11 days', true]; + yield [true, true, '-5 days', false]; + yield [true, false, '-5 days', false]; + // changing a value in the last lockdown period is not allowed outside grace period + yield [false, false, '+5 days', true]; // changing outside grace period is allowed with grace and full permission - yield [false, true, '+5 days', '+11 days', false]; - yield [true, false, '+5 days', '+11 days', false]; - yield [true, true, '+5 days', '+11 days', false]; + yield [false, true, '+5 days', false]; + yield [true, false, '+5 days', false]; + yield [true, true, '+5 days', false]; } #[DataProvider('getConfigTestData')] @@ -201,9 +181,7 @@ class TimesheetLockdownValidatorTest extends ConstraintValidatorTestCase $timesheet = new Timesheet(); $timesheet->setBegin($begin); - $now = new \DateTime('first day of this month'); - - $constraint = new TimesheetLockdown(['message' => 'myMessage', 'now' => $now]); + $constraint = new TimesheetLockdown(); $this->validator->validate($timesheet, $constraint); diff --git a/tests/Validator/Constraints/TimesheetLongRunningTest.php b/tests/Validator/Constraints/TimesheetLongRunningTest.php index 8fd9eff19..34a13c925 100644 --- a/tests/Validator/Constraints/TimesheetLongRunningTest.php +++ b/tests/Validator/Constraints/TimesheetLongRunningTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetLongRunning; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetLongRunning::class)] -class TimesheetLongRunningTest extends TestCase +class TimesheetLongRunningTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetLongRunning()); + $this->assertTimesheetConstraint(new TimesheetLongRunning()); } } diff --git a/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php b/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php index 7e7acd573..d56537d1e 100644 --- a/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetLongRunningValidatorTest.php @@ -56,7 +56,7 @@ class TimesheetLongRunningValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetLongRunning(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetLongRunning()); } public function testLongRunningTriggers(): void diff --git a/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php b/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php index bc2cf794b..2d68fdccf 100644 --- a/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetMultiUpdateValidatorTest.php @@ -50,7 +50,7 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase $timesheet->setActivity($activity); $timesheet->setProject($project2); - $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(message: 'myMessage')); $this->buildViolation('Project mismatch, project specific activity and timesheet project are different.') ->atPath('property.path.project') @@ -65,7 +65,7 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase ->setProject(new Project()) ; - $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(message: 'myMessage')); $this->buildViolation('You need to choose an activity, if the project should be changed.') ->atPath('property.path.activity') @@ -80,7 +80,7 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase ->setActivity((new Activity())->setProject(new Project())) ; - $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(message: 'myMessage')); $this->buildViolation('Missing project.') ->atPath('property.path.project') @@ -94,7 +94,7 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase $timesheet->setHourlyRate(10.12); $timesheet->setFixedRate(123.45); - $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(message: 'myMessage')); $this->buildViolation('Cannot set hourly rate and fixed rate at the same time.') ->atPath('property.path.fixedRate') @@ -120,7 +120,7 @@ class TimesheetMultiUpdateValidatorTest extends ConstraintValidatorTestCase $timesheet->setActivity($activity); $timesheet->setProject($project); - $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUpdateConstraint(message: 'myMessage')); $this->buildViolation('Cannot assign a disabled activity.') ->atPath('property.path.activity') diff --git a/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php b/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php index 6e11c6d8d..10c2e64d9 100644 --- a/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetMultiUserValidatorTest.php @@ -40,7 +40,7 @@ class TimesheetMultiUserValidatorTest extends ConstraintValidatorTestCase { $timesheet = new MultiUserTimesheet(); - $this->validator->validate($timesheet, new TimesheetMultiUser(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetMultiUser(message: 'myMessage')); $this->buildViolation('You must select at least one user or team.') ->atPath('property.path.users') diff --git a/tests/Validator/Constraints/TimesheetNegativeDurationTest.php b/tests/Validator/Constraints/TimesheetNegativeDurationTest.php index 84ebc1624..e4f3ef0ea 100644 --- a/tests/Validator/Constraints/TimesheetNegativeDurationTest.php +++ b/tests/Validator/Constraints/TimesheetNegativeDurationTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetNegativeDuration; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetNegativeDuration::class)] -class TimesheetNegativeDurationTest extends TestCase +class TimesheetNegativeDurationTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetNegativeDuration()); + $this->assertTimesheetConstraint(new TimesheetNegativeDuration()); } } diff --git a/tests/Validator/Constraints/TimesheetNegativeDurationValidatorTest.php b/tests/Validator/Constraints/TimesheetNegativeDurationValidatorTest.php index c7e86b804..4b04faf8d 100644 --- a/tests/Validator/Constraints/TimesheetNegativeDurationValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetNegativeDurationValidatorTest.php @@ -40,7 +40,7 @@ class TimesheetNegativeDurationValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetNegativeDuration(['message' => 'Duration cannot be negative.'])); + $this->validator->validate(new NotBlank(), new TimesheetNegativeDuration()); } public function testNegativeDurationIsNotAllowed(): void @@ -51,7 +51,7 @@ class TimesheetNegativeDurationValidatorTest extends ConstraintValidatorTestCase $timesheet->setEnd(clone $begin); $timesheet->setBreak(3600); - $this->validator->validate($timesheet, new TimesheetNegativeDuration(['message' => 'Duration cannot be negative.'])); + $this->validator->validate($timesheet, new TimesheetNegativeDuration()); $this->buildViolation('Duration cannot be negative.') ->atPath('property.path.duration') @@ -69,7 +69,7 @@ class TimesheetNegativeDurationValidatorTest extends ConstraintValidatorTestCase $this->validator = $this->createValidator(); $this->validator->initialize($this->context); - $this->validator->validate($timesheet, new TimesheetNegativeDuration(['message' => 'Duration cannot be negative.'])); + $this->validator->validate($timesheet, new TimesheetNegativeDuration()); $this->assertNoViolation(); } @@ -84,7 +84,7 @@ class TimesheetNegativeDurationValidatorTest extends ConstraintValidatorTestCase $this->validator = $this->createValidator(); $this->validator->initialize($this->context); - $this->validator->validate($timesheet, new TimesheetNegativeDuration(['message' => 'Duration cannot be negative.'])); + $this->validator->validate($timesheet, new TimesheetNegativeDuration()); $this->assertNoViolation(); } diff --git a/tests/Validator/Constraints/TimesheetOverlappingTest.php b/tests/Validator/Constraints/TimesheetOverlappingTest.php index 171ad0a68..79463dea5 100644 --- a/tests/Validator/Constraints/TimesheetOverlappingTest.php +++ b/tests/Validator/Constraints/TimesheetOverlappingTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetOverlapping; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetOverlapping::class)] -class TimesheetOverlappingTest extends TestCase +class TimesheetOverlappingTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetOverlapping()); + $this->assertTimesheetConstraint(new TimesheetOverlapping()); } } diff --git a/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php b/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php index 3d2d25dd9..f9f59bb95 100644 --- a/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetOverlappingValidatorTest.php @@ -59,7 +59,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetOverlapping()); } public function testOverlappingDisallowedWithRecords(): void @@ -70,7 +70,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase $timesheet->setBegin($begin); $timesheet->setEnd($end); - $this->validator->validate($timesheet, new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetOverlapping()); $this->buildViolation('You already have an entry for this time.') ->atPath('property.path.begin_date') @@ -89,7 +89,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase $timesheet->setBegin($begin); $timesheet->setEnd($end); - $this->validator->validate($timesheet, new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetOverlapping()); self::assertEmpty($this->context->getViolations()); } @@ -104,7 +104,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase $timesheet->setBegin($begin); $timesheet->setEnd($end); - $this->validator->validate($timesheet, new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetOverlapping()); self::assertEmpty($this->context->getViolations()); } @@ -119,7 +119,7 @@ class TimesheetOverlappingValidatorTest extends ConstraintValidatorTestCase $timesheet->setBegin($begin); $timesheet->setEnd($end); - $this->validator->validate($timesheet, new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetOverlapping()); self::assertEmpty($this->context->getViolations()); } } diff --git a/tests/Validator/Constraints/TimesheetRestartTest.php b/tests/Validator/Constraints/TimesheetRestartTest.php index 0eae82711..fe87c7cd8 100644 --- a/tests/Validator/Constraints/TimesheetRestartTest.php +++ b/tests/Validator/Constraints/TimesheetRestartTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetRestart; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetRestart::class)] -class TimesheetRestartTest extends TestCase +class TimesheetRestartTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetRestart()); + $this->assertTimesheetConstraint(new TimesheetRestart()); } } diff --git a/tests/Validator/Constraints/TimesheetRestartValidatorTest.php b/tests/Validator/Constraints/TimesheetRestartValidatorTest.php index 06e55e4df..295826d07 100644 --- a/tests/Validator/Constraints/TimesheetRestartValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetRestartValidatorTest.php @@ -59,7 +59,7 @@ class TimesheetRestartValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetOverlapping(['message' => 'myMessage'])); + $this->validator->validate(new NotBlank(), new TimesheetOverlapping()); } #[DataProvider('getTestData')] @@ -82,7 +82,7 @@ class TimesheetRestartValidatorTest extends ConstraintValidatorTestCase ->setProject($project) ; - $this->validator->validate($timesheet, new TimesheetRestart(['message' => 'myMessage'])); + $this->validator->validate($timesheet, new TimesheetRestart()); if (null !== $property) { $this->buildViolation('You are not allowed to start this timesheet record.') diff --git a/tests/Validator/Constraints/TimesheetZeroDurationTest.php b/tests/Validator/Constraints/TimesheetZeroDurationTest.php index 022fea833..a1308c405 100644 --- a/tests/Validator/Constraints/TimesheetZeroDurationTest.php +++ b/tests/Validator/Constraints/TimesheetZeroDurationTest.php @@ -9,16 +9,14 @@ namespace App\Tests\Validator\Constraints; -use App\Validator\Constraints\TimesheetConstraint; use App\Validator\Constraints\TimesheetZeroDuration; use PHPUnit\Framework\Attributes\CoversClass; -use PHPUnit\Framework\TestCase; #[CoversClass(TimesheetZeroDuration::class)] -class TimesheetZeroDurationTest extends TestCase +class TimesheetZeroDurationTest extends AbstractConstraintTestCase { public function testIsTimesheetConstraint(): void { - self::assertInstanceOf(TimesheetConstraint::class, new TimesheetZeroDuration()); + $this->assertTimesheetConstraint(new TimesheetZeroDuration()); } } diff --git a/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php b/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php index dc64e4a18..6d9597af0 100644 --- a/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php +++ b/tests/Validator/Constraints/TimesheetZeroDurationValidatorTest.php @@ -56,7 +56,7 @@ class TimesheetZeroDurationValidatorTest extends ConstraintValidatorTestCase { $this->expectException(UnexpectedTypeException::class); - $this->validator->validate(new NotBlank(), new TimesheetZeroDuration(['message' => 'Duration cannot be zero.'])); + $this->validator->validate(new NotBlank(), new TimesheetZeroDuration()); } private function prepareTimesheet(): Timesheet @@ -75,7 +75,7 @@ class TimesheetZeroDurationValidatorTest extends ConstraintValidatorTestCase { $timesheet = $this->prepareTimesheet(); - $this->validator->validate($timesheet, new TimesheetZeroDuration(['message' => 'Duration cannot be zero.'])); + $this->validator->validate($timesheet, new TimesheetZeroDuration()); $this->buildViolation('Duration cannot be zero.') ->atPath('property.path.duration') @@ -90,7 +90,7 @@ class TimesheetZeroDurationValidatorTest extends ConstraintValidatorTestCase $timesheet = $this->prepareTimesheet(); - $this->validator->validate($timesheet, new TimesheetZeroDuration(['message' => 'Duration cannot be zero.'])); + $this->validator->validate($timesheet, new TimesheetZeroDuration()); $this->assertNoViolation(); } diff --git a/tests/Validator/Constraints/UserValidatorTest.php b/tests/Validator/Constraints/UserValidatorTest.php index b0b645716..4822e56cf 100644 --- a/tests/Validator/Constraints/UserValidatorTest.php +++ b/tests/Validator/Constraints/UserValidatorTest.php @@ -42,14 +42,14 @@ class UserValidatorTest extends ConstraintValidatorTestCase public function testNullIsValid(): void { - $this->validator->validate(null, new User(['message' => 'myMessage'])); // @phpstan-ignore argument.type + $this->validator->validate(null, new User(message: 'myMessage')); // @phpstan-ignore argument.type $this->assertNoViolation(); } public function testNonUserIsValid(): void { - $this->validator->validate(new TestUserEntity(), new User(['message' => 'myMessage'])); // @phpstan-ignore argument.type + $this->validator->validate(new TestUserEntity(), new User(message: 'myMessage')); // @phpstan-ignore argument.type $this->assertNoViolation(); } @@ -59,7 +59,7 @@ class UserValidatorTest extends ConstraintValidatorTestCase $user = new UserEntity(); $user->setUserIdentifier('foo'); $user->setEmail('test'); - $this->validator->validate($user, new User(['message' => 'myMessage'])); + $this->validator->validate($user, new User(message: 'myMessage')); $this->assertNoViolation(); } @@ -70,7 +70,7 @@ class UserValidatorTest extends ConstraintValidatorTestCase $user->setUserIdentifier('foo'); $user->setEmail('foo@example.com'); - $this->validator->validate($user, new User(['message' => 'myMessage'])); + $this->validator->validate($user, new User(message: 'myMessage')); $this->assertNoViolation(); } diff --git a/tests/Voter/AbstractVoterTestCase.php b/tests/Voter/AbstractVoterTestCase.php index 48b904fee..1a4a9fd98 100644 --- a/tests/Voter/AbstractVoterTestCase.php +++ b/tests/Voter/AbstractVoterTestCase.php @@ -42,7 +42,6 @@ abstract class AbstractVoterTestCase extends TestCase $reflection = new \ReflectionClass($user); $property = $reflection->getProperty('id'); - $property->setAccessible(true); $property->setValue($user, $id); return $user; diff --git a/tests/WorkingTime/Mode/WorkingTimeModeFactoryTest.php b/tests/WorkingTime/Mode/WorkingTimeModeFactoryTest.php index beab52d5e..2c4339a4b 100644 --- a/tests/WorkingTime/Mode/WorkingTimeModeFactoryTest.php +++ b/tests/WorkingTime/Mode/WorkingTimeModeFactoryTest.php @@ -44,7 +44,7 @@ class WorkingTimeModeFactoryTest extends TestCase $sut = new WorkingTimeModeFactory($modes, $logger); $user = new User(); - $user->setUsername('foo-bar'); + $user->setUserIdentifier('bar'); $user->setWorkContractMode('foo'); self::assertInstanceOf(WorkingTimeModeNone::class, $sut->getModeForUser($user)); } diff --git a/tests/WorkingTime/Model/MonthTest.php b/tests/WorkingTime/Model/MonthTest.php index c0b94c39b..2920da5dc 100644 --- a/tests/WorkingTime/Model/MonthTest.php +++ b/tests/WorkingTime/Model/MonthTest.php @@ -21,7 +21,7 @@ class MonthTest extends TestCase public function testDefaults(): void { $user = new User(); - $user->setUsername('foo-bar'); + $user->setUserIdentifier('foo-bar'); $months = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; foreach($months as $key => $days) { diff --git a/tests/phpstan.neon b/tests/phpstan.neon index 45dd4e409..73c3b86f8 100644 --- a/tests/phpstan.neon +++ b/tests/phpstan.neon @@ -261,16 +261,6 @@ parameters: count: 23 path: API/TeamControllerTest.php - - - message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#" - count: 1 - path: API/TimesheetControllerTest.php - - - - message: "#^Cannot access offset 0 on mixed\\.$#" - count: 1 - path: API/TimesheetControllerTest.php - - message: "#^Cannot call method getDescription\\(\\) on App\\\\Entity\\\\Timesheet\\|null\\.$#" count: 1 @@ -296,11 +286,6 @@ parameters: count: 1 path: API/TimesheetControllerTest.php - - - message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, mixed given\\.$#" - count: 1 - path: API/TimesheetControllerTest.php - - message: "#^Parameter \\#1 \\$hashedPassword of method Symfony\\\\Component\\\\PasswordHasher\\\\PasswordHasherInterface\\:\\:verify\\(\\) expects string, string\\|null given\\.$#" count: 1 @@ -703,7 +688,7 @@ parameters: - message: "#^Parameter \\#1 \\$hashedPassword of method Symfony\\\\Component\\\\PasswordHasher\\\\PasswordHasherInterface\\:\\:verify\\(\\) expects string, string\\|null given\\.$#" - count: 8 + count: 4 path: Controller/ProfileControllerTest.php - @@ -726,16 +711,6 @@ parameters: count: 2 path: Controller/ProjectControllerTest.php - - - message: "#^Cannot call method setEnd\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#" - count: 2 - path: Controller/ProjectControllerTest.php - - - - message: "#^Cannot call method setMetaField\\(\\) on App\\\\Entity\\\\Project\\|null\\.$#" - count: 2 - path: Controller/ProjectControllerTest.php - - message: "#^Method App\\\\Tests\\\\Controller\\\\ProjectControllerTest\\:\\:assertAddRate\\(\\) has parameter \\$projectId with no type specified\\.$#" count: 1 @@ -766,16 +741,6 @@ parameters: count: 1 path: Controller/ProjectControllerTest.php - - - message: "#^Parameter \\#1 \\$entity of method Doctrine\\\\ORM\\\\EntityManager\\:\\:persist\\(\\) expects object, App\\\\Entity\\\\Project\\|null given\\.$#" - count: 2 - path: Controller/ProjectControllerTest.php - - - - message: "#^Parameter \\#1 \\$project of method App\\\\Entity\\\\Team\\:\\:addProject\\(\\) expects App\\\\Entity\\\\Project, App\\\\Entity\\\\Project\\|null given\\.$#" - count: 1 - path: Controller/ProjectControllerTest.php - - message: "#^Parameter \\#1 \\$projects of method App\\\\Tests\\\\DataFixtures\\\\ActivityFixtures\\:\\:setProjects\\(\\) expects array\\, array\\ given\\.$#" count: 2 @@ -1346,11 +1311,6 @@ parameters: count: 1 path: Form/Type/DurationTypeTest.php - - - message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:getExtensions\\(\\) has no return type specified\\.$#" - count: 1 - path: Form/Type/QuickEntryTimesheetTypeTest.php - - message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:getTestData\\(\\) has no return type specified\\.$#" count: 1 @@ -1801,16 +1761,6 @@ parameters: count: 1 path: Repository/TimesheetInvoiceItemRepositoryTest.php - - - message: "#^Cannot call method getId\\(\\) on mixed\\.$#" - count: 2 - path: Repository/TimesheetRepositoryTest.php - - - - message: "#^Cannot call method getName\\(\\) on mixed\\.$#" - count: 2 - path: Repository/TimesheetRepositoryTest.php - - message: "#^Method App\\\\Tests\\\\Saml\\\\SamlProviderTest\\:\\:getSamlProvider\\(\\) has parameter \\$mapping with no value type specified in iterable type array\\.$#" count: 1 diff --git a/translations/messages.ar.xlf b/translations/messages.ar.xlf index f60d32f1a..9f86ca3d3 100644 --- a/translations/messages.ar.xlf +++ b/translations/messages.ar.xlf @@ -46,14 +46,6 @@ user_profile ملفي - - api_token - كلمة مرور API - - - api_token_repeat - كرر كلمة مرور API - menu.homepage لوحة القيادة @@ -1814,10 +1806,6 @@ Expiry date تاريخ انتهاء الصلاحية - - api_password_deprecated - كلمات مرور واجهة برمجة التطبيقات (API) قديمة: يُرجى استخدام رموز واجهة برمجة التطبيقات (API) بدلاً من ذلك. - completed_month_pdf ملف PDF الشهر المنتهي diff --git a/translations/messages.bg.xlf b/translations/messages.bg.xlf index 2d555776e..b190f85ca 100644 --- a/translations/messages.bg.xlf +++ b/translations/messages.bg.xlf @@ -134,14 +134,6 @@ user_profile Моят профил - - api_token - API парола - - - api_token_repeat - Повторете паролата за API - login_required Липсва разрешение. Пренасочване към вход? @@ -1658,10 +1650,6 @@ api_token_hidden Това е единственият път, когато този ключ някога ще бъде показан! Затова го пазете и се уверете, че сте го копирали преди затварянето на този прозорец. - - api_password_deprecated - Паролите на API са остарели: моля, използвайте вместо това API маркери. - hours_per_day Часове на ден diff --git a/translations/messages.ca.xlf b/translations/messages.ca.xlf index 40cb0b17c..a8c5465b8 100644 --- a/translations/messages.ca.xlf +++ b/translations/messages.ca.xlf @@ -166,14 +166,6 @@ user_profile El meu perfil - - api_token - Contrasenya de l'API - - - api_token_repeat - Repeteix la contrasenya de l'API - login_required Permís absent. Redirigir a l'inici de sessió? @@ -1770,10 +1762,6 @@ api_token_hidden Aquesta és l'única vegada que es mostrarà aquesta clau! Guardeu-la de manera segura i assegureu-vos d'haver-la copiat abans de tancar aquesta finestra. - - api_password_deprecated - Les contrasenyes de l'API estan obsoletes: utilitzeu tokens de l'API en el seu lloc. - hours_per_day Hores per dia diff --git a/translations/messages.cs.xlf b/translations/messages.cs.xlf index 01be0a7ca..5739dc6ec 100644 --- a/translations/messages.cs.xlf +++ b/translations/messages.cs.xlf @@ -62,14 +62,6 @@ user_profile Můj profil - - api_token - API heslo - - - api_token_repeat - Potvrdit API heslo - menu.homepage Nástěnka @@ -1654,10 +1646,6 @@ api_token_hidden Toto je jediný čas, kdy tento klíč kdy bude zobrazen! Tak ho udržujte v bezpečí a ujistětete se, že jste si ho zkopírovali před zavřením tohoto okna. - - api_password_deprecated - API hesla jsou zastaralá: prosím používejte místo nich API tokeny. - absence_comment_mandatory Nepřítomnost: Komentář je povinné pole diff --git a/translations/messages.da.xlf b/translations/messages.da.xlf index b1ae4251a..2f6573299 100644 --- a/translations/messages.da.xlf +++ b/translations/messages.da.xlf @@ -70,14 +70,6 @@ user_profile Min profil - - api_token - API adgangskode - - - api_token_repeat - Gentag API adgangskode - login_required Mangler tilladelse. Omdirigér til log ind? @@ -1806,10 +1798,6 @@ api_token_hidden Dette er den eneste gang at denne nøgle nogensinde vil brlive vist! Opbevar den sikkert og sørg for at du har kopieret den, inden du lukker dette vindue. - - api_password_deprecated - API adgangskode er forældet: B rug venligst API token i stedet. - hours_per_day Timer pr. dag diff --git a/translations/messages.de.xlf b/translations/messages.de.xlf index 9dd41156d..fa9d1b1a0 100644 --- a/translations/messages.de.xlf +++ b/translations/messages.de.xlf @@ -138,14 +138,6 @@ user_profile Mein Profil - - api_token - API-Passwort - - - api_token_repeat - API-Passwort wiederholen - login_required Fehlende Berechtigung. Zur Anmeldung wechseln? @@ -1706,10 +1698,6 @@ api_token_hidden Dies ist das einzige Mal, dass der Token angezeigt wird! Bewahren Sie ihn gut auf und vergewissern Sie sich, dass Sie ihn notiert haben, bevor Sie dieses Fenster schließen. - - api_password_deprecated - API Passwörter sind veraltet: bitte nutzen Sie stattdessen API-Tokens. - hours_per_day Stunden pro Tag diff --git a/translations/messages.de_CH.xlf b/translations/messages.de_CH.xlf index ff2226def..48af02036 100644 --- a/translations/messages.de_CH.xlf +++ b/translations/messages.de_CH.xlf @@ -14,14 +14,6 @@ menu.homepage Dashboard - - api_token_repeat - API-Passwort wiederholen - - - api_token - API-Passwort - invoice_tax_number Mehrwertsteuer-ID-Nr.: @@ -1822,10 +1814,6 @@ api_token_hidden Dies ist das einzige Mal, dass der Token angezeigt wird! Bewahren Sie ihn gut auf und vergewissern Sie sich, dass Sie ihn notiert haben, bevor Sie dieses Fenster schliessen. - - api_password_deprecated - API Passwörter sind veraltet: bitte nutzen Sie stattdessen API-Tokens. - hours_per_day Stunden pro Tag diff --git a/translations/messages.el.xlf b/translations/messages.el.xlf index 9b9019f50..65d0fe60a 100644 --- a/translations/messages.el.xlf +++ b/translations/messages.el.xlf @@ -122,14 +122,6 @@ user_profile Το Προφίλ μου - - api_token - Διαπιστευτήριο API - - - api_token_repeat - Επανάληψη διαπιστευτηρίου API - login_required Ληγμένη συνεδρία. Ανακατεύθυνση στην οθόνη σύνδεσης; @@ -1302,10 +1294,6 @@ booking_allow_only_work_days Να επιτρέπονται καταχωρήσεις χρόνου μόνο για τις ημέρες για τις οποίες οι αναμενόμενες ώρες ορίζονται στη σύμβαση εργασίας - - api_password_deprecated - Οι κωδικοί πρόσβασης API είναι απαρχαιωμένοι: παρακαλούμε χρησιμοποιήστε αντί αυτών τα tokens API. - Project number Αριθμός έργου diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 4147523ab..2ad3cff88 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -138,14 +138,6 @@ user_profile My profile - - api_token - API password - - - api_token_repeat - Repeat API password - login_required Missing permission. Redirect to login? @@ -1710,10 +1702,6 @@ api_token_hidden This is the only time this key will ever be displayed! So keep it safe and make sure you've copied it down before closing this window. - - api_password_deprecated - API passwords are outdated: please use API tokens instead. - hours_per_day Hours per day diff --git a/translations/messages.eo.xlf b/translations/messages.eo.xlf index 61d175380..07a24201f 100644 --- a/translations/messages.eo.xlf +++ b/translations/messages.eo.xlf @@ -86,14 +86,6 @@ user_profile Mia profilo - - api_token - API-pasvorto - - - api_token_repeat - Ripetu API-pasvorton - login_required Mankas permeso. Redirekti al ensaluto? diff --git a/translations/messages.es.xlf b/translations/messages.es.xlf index e5ee990b5..feba2e2ce 100644 --- a/translations/messages.es.xlf +++ b/translations/messages.es.xlf @@ -66,14 +66,6 @@ user_profile Mi perfil - - api_token - Contraseña de API - - - api_token_repeat - Repetir contraseña de API - login_required Sin permisos. ¿Volver al inicio de sesión? @@ -1638,10 +1630,6 @@ Expiry date Vencimiento - - api_password_deprecated - Las contraseñas de la API están obsoletas: en su lugar, utilice los tokens de la API. - Last usage Usado por última vez diff --git a/translations/messages.et.xlf b/translations/messages.et.xlf index 6f12d6b55..386d2ecf6 100644 --- a/translations/messages.et.xlf +++ b/translations/messages.et.xlf @@ -150,14 +150,6 @@ user_profile Minu profiil - - api_token - API salasõna - - - api_token_repeat - Korda API salasõna - login_required Puudub luba. Suunan ümber sisselogimisele? diff --git a/translations/messages.eu.xlf b/translations/messages.eu.xlf index 5502eb094..6c8d8e937 100644 --- a/translations/messages.eu.xlf +++ b/translations/messages.eu.xlf @@ -74,14 +74,6 @@ user_profile Nire kontua - - api_token - API pasahitza - - - api_token_repeat - API pasahitza errepikatu - login_required Baimena falta da. Saio hasierara bueltatu? diff --git a/translations/messages.fa.xlf b/translations/messages.fa.xlf index ac9d95e59..2186152a9 100644 --- a/translations/messages.fa.xlf +++ b/translations/messages.fa.xlf @@ -94,14 +94,6 @@ user_profile پروفایل من - - api_token - پسورد API - - - api_token_repeat - تکرار پسورد API - login_required مجوز از دست رفته است. تغییر مسیر برای ورود به سیستم؟ @@ -1794,10 +1786,6 @@ api_token_hidden این تنها باری است که این کلید نمایش داده می‌شود! پس آن را در جای امنی نگه دارید و قبل از بستن این پنجره، مطمئن شوید که آن را کپی کرده‌اید. - - api_password_deprecated - رمزهای عبور API قدیمی هستند: لطفاً به جای آنها از توکن‌های API استفاده کنید. - hours_per_day ساعت در روز diff --git a/translations/messages.fi.xlf b/translations/messages.fi.xlf index c79675bdd..be3e54072 100644 --- a/translations/messages.fi.xlf +++ b/translations/messages.fi.xlf @@ -86,14 +86,6 @@ user_profile Oma profiili - - api_token - API salasana - - - api_token_repeat - Toista API salasana - login_required Puuttuvat oikeudet. Uudelleen ohjataanko kirjautumiseen? @@ -1630,10 +1622,6 @@ api_token_hidden Tämä on ainoa kerta, kun tämä avain näytetään! Pidä se siis turvassa ja varmista, että olet kopioinut sen ennen tämän ikkunan sulkemista. - - api_password_deprecated - API-salasanat ovat vanhentuneet: käytä sen sijaan API-tunnuksia. - Expected number of hours Odotetut tunnit diff --git a/translations/messages.fo.xlf b/translations/messages.fo.xlf index 8643a4e56..1179c3856 100644 --- a/translations/messages.fo.xlf +++ b/translations/messages.fo.xlf @@ -34,14 +34,6 @@ user_profile Mín vangi - - api_token - API loyniorð - - - api_token_repeat - Endurtak API loyniorð - menu.logout Logga av diff --git a/translations/messages.fr.xlf b/translations/messages.fr.xlf index 533ae459a..58b137a9b 100644 --- a/translations/messages.fr.xlf +++ b/translations/messages.fr.xlf @@ -62,14 +62,6 @@ user_profile Mon profil - - api_token - Mot de passe de l'API - - - api_token_repeat - Répéter le mot de passe de l'API - menu.homepage Tableau de bord @@ -1654,10 +1646,6 @@ Last usage Dernière utilisation - - api_password_deprecated - Les mots de passe d'API sont périmés, à la place, utilisez les jetons d'API. - api_token_hidden Cette clé ne sera affichée qu’une seule fois ! Copiez la et conservez la en sécurité avant de fermer la fenêtre. diff --git a/translations/messages.he.xlf b/translations/messages.he.xlf index aed28119e..d95d99816 100644 --- a/translations/messages.he.xlf +++ b/translations/messages.he.xlf @@ -86,14 +86,6 @@ user_profile הפרופיל שלי - - api_token - סיסמת API - - - api_token_repeat - אימות סיסמת API - login_required חסרה הרשאה. להפנות לכניסה למערכת? @@ -1642,10 +1634,6 @@ Last usage שימוש אחרון - - api_password_deprecated - השימוש בסיסמאות API הופסק: נא להשתמש באסימוני API במקום. - api_token_hidden זאת הפעם היחידה שהמפתח הזה יוצג אי־פעם! לכן כדאי לוודא שהוא שמור בבטחה ושהוא הועתק כראוי בטרם סגירת החלון הזה. diff --git a/translations/messages.hr.xlf b/translations/messages.hr.xlf index a1d9c0e59..648acf1cc 100644 --- a/translations/messages.hr.xlf +++ b/translations/messages.hr.xlf @@ -122,14 +122,6 @@ user_profile Moj profil - - api_token - API lozinka - - - api_token_repeat - Ponovi API lozinku - login_required Nedostaje dozvola. Preusmjeriti na prijavu? @@ -1634,10 +1626,6 @@ Expiry date Datum isteka - - api_password_deprecated - API lozinke su zastarjele: umjesto njih koristi API tokene. - Activity number Broj aktivnosti diff --git a/translations/messages.hu.xlf b/translations/messages.hu.xlf index 9a649148c..086517264 100644 --- a/translations/messages.hu.xlf +++ b/translations/messages.hu.xlf @@ -62,14 +62,6 @@ user_profile Profilom - - api_token - API jelszó - - - api_token_repeat - API jelszó ismétlese - menu.homepage Kezdőlap @@ -1702,10 +1694,6 @@ please_choose Kérlek válassz - - api_password_deprecated - Az API jelszavak elavultak: kérlek használd helyettük az API tokeneket. - address_deprecated Ez a mező hamarosan eltávolításra kerül. Kérlek írd át a címet, hogy továbbra is érvényes számlák generálódjanak (pl. e-számlázás céljából). diff --git a/translations/messages.id.xlf b/translations/messages.id.xlf index 03a7bd9fc..7fb0b71df 100644 --- a/translations/messages.id.xlf +++ b/translations/messages.id.xlf @@ -218,10 +218,6 @@ file Berkas - - api_token - Kata sandi API - help Dokumentasi @@ -706,10 +702,6 @@ active Aktif - - api_token_repeat - Ulangi kata sandi API - login_required Izin tidak ditemukan. Alihkan ke log masuk? @@ -1794,10 +1786,6 @@ Last usage Penggunaan terakhir - - api_password_deprecated - Kata sandi API telah usang: sebagai gantinya, tolong gunakan token API. - hours_per_week Jam perminggu diff --git a/translations/messages.it.xlf b/translations/messages.it.xlf index f3e01dcc6..71762a456 100644 --- a/translations/messages.it.xlf +++ b/translations/messages.it.xlf @@ -86,14 +86,6 @@ user_profile Il mio profilo - - api_token - Password API - - - api_token_repeat - Ripeti password API - login_required Autorizzazione mancante. Reindirizzare all'accesso? @@ -1634,10 +1626,6 @@ Project number Numero progetto - - api_password_deprecated - Le password API sono obsolete: usa invece i token API. - Expiry date Data di scadenza diff --git a/translations/messages.ja.xlf b/translations/messages.ja.xlf index 9dd048db1..701facdc3 100644 --- a/translations/messages.ja.xlf +++ b/translations/messages.ja.xlf @@ -62,14 +62,6 @@ user_profile プロフィール - - api_token - API パスワード - - - api_token_repeat - API パスワード(再入力) - menu.homepage ダッシュボード diff --git a/translations/messages.ko.xlf b/translations/messages.ko.xlf index 2da8087dd..0ac3733dc 100644 --- a/translations/messages.ko.xlf +++ b/translations/messages.ko.xlf @@ -62,14 +62,6 @@ user_profile 나의 프로필 - - api_token - API 비밀번호 - - - api_token_repeat - API 비밀번호 재확인 - menu.homepage 대시보드 diff --git a/translations/messages.lv.xlf b/translations/messages.lv.xlf index 971b03fa4..211063f06 100644 --- a/translations/messages.lv.xlf +++ b/translations/messages.lv.xlf @@ -130,14 +130,6 @@ user_profile Mans profils - - api_token - API parole - - - api_token_repeat - Atkārtojiet API paroli - login_required Nav piekļuves tiesību. Vai vēlaties pāriet uz pieteikšanās lapu? diff --git a/translations/messages.mk.xlf b/translations/messages.mk.xlf index c3ecf00e6..82ce398cb 100644 --- a/translations/messages.mk.xlf +++ b/translations/messages.mk.xlf @@ -138,14 +138,6 @@ user_profile Мојот профил - - api_token - API лозинка - - - api_token_repeat - Повтори API лозинка - login_required Недостасува дозвола. Пренасочи кон најавување? @@ -1770,10 +1762,6 @@ api_token_hidden Ова е единствениот пат кога овој клуч ќе се прикаже! Затоа, чувајте го на безбедно и осигурајте се дека сте го копирале пред да го затворите овој прозорец. - - api_password_deprecated - API лозинките се застарени: наместо тоа користете API токени. - hours_per_day Часови на ден diff --git a/translations/messages.nb_NO.xlf b/translations/messages.nb_NO.xlf index ae2eb201e..4c4450f9d 100644 --- a/translations/messages.nb_NO.xlf +++ b/translations/messages.nb_NO.xlf @@ -86,14 +86,6 @@ user_profile Min profil - - api_token - API-passord - - - api_token_repeat - Gjenta API-passord - login_required Manglende tillatelse. Videresend til innlogging? @@ -1794,10 +1786,6 @@ api_token_hidden Dette er den eneste gangen nøkkelen vil vises! Oppbevar den trygt og sørg for at du har kopiert den før du lukker vinduet. - - api_password_deprecated - API-passord er foreldet: vennligst bruk API-nøkler i stedet. - hours_per_day Timer pr. dag diff --git a/translations/messages.nl.xlf b/translations/messages.nl.xlf index a1425459b..e5cba2afc 100644 --- a/translations/messages.nl.xlf +++ b/translations/messages.nl.xlf @@ -66,14 +66,6 @@ user_profile Mijn profiel - - api_token - API wachtwoord - - - api_token_repeat - Herhaal API wachtwoord - login_required Ontbrekende rechten. Terug naar het aanmeldscherm? @@ -1614,10 +1606,6 @@ api_token_hidden Dit is de enige keer dat deze token wordt getoond. Bewaar deze veilig voordat je dit scherm afsluit. - - api_password_deprecated - Het gebruik van API wachtworden is verouderd, gebruik in de plaats daarvan API tokens. - Importer Importeren diff --git a/translations/messages.pa.xlf b/translations/messages.pa.xlf index 8edd1d7f1..f9454566e 100644 --- a/translations/messages.pa.xlf +++ b/translations/messages.pa.xlf @@ -26,10 +26,6 @@ security.unlock.button ਅਨਲੌਕ - - api_token - API ਪਾਸਵਰਡ - customers ਗਾਹਕ @@ -122,10 +118,6 @@ projects ਪ੍ਰਾਜੈਕਟਾਂ - - api_token_repeat - API ਪਾਸਵਰਡ ਦੁਬਾਰਾ - confirm ਪੁਸ਼ਟੀ ਕਰੋ diff --git a/translations/messages.pl.xlf b/translations/messages.pl.xlf index f2b0c87a6..76deb4e3c 100644 --- a/translations/messages.pl.xlf +++ b/translations/messages.pl.xlf @@ -74,14 +74,6 @@ user_profile Mój profil - - api_token - Hasło API - - - api_token_repeat - Powtórz hasło API - login_required Brak uprawnień. Przekierować na stronę logowania? @@ -1646,10 +1638,6 @@ Expiry date Data wygaśnięcia - - api_password_deprecated - Hasła API są nieaktualne: zamiast tego użyj tokenów API. - absence_comment_mandatory Nieobecność: Komentarz jest polem obowiązkowym diff --git a/translations/messages.pt.xlf b/translations/messages.pt.xlf index 681f18cf4..0d8334156 100644 --- a/translations/messages.pt.xlf +++ b/translations/messages.pt.xlf @@ -62,14 +62,6 @@ user_profile Meu perfil - - api_token - Palavra-passe da API - - - api_token_repeat - Repita a palavra-passe da API - menu.homepage Painel principal @@ -1638,10 +1630,6 @@ Expiry date Data de expiração - - api_password_deprecated - As palavras-passe da API estão desatualizadas: utilize antes os tokens da API. - Last usage Última utilização diff --git a/translations/messages.pt_BR.xlf b/translations/messages.pt_BR.xlf index a064a3050..f9d20dd75 100644 --- a/translations/messages.pt_BR.xlf +++ b/translations/messages.pt_BR.xlf @@ -62,14 +62,6 @@ user_profile Meu Perfil - - api_token - Senha API - - - api_token_repeat - Repita Senha da API - menu.homepage Painel @@ -1634,10 +1626,6 @@ Activity number Numeração da atividade - - api_password_deprecated - As senhas de API estão desatualizadas: em vez disso, use tokens de API. - Expiry date Data de vencimento diff --git a/translations/messages.ro.xlf b/translations/messages.ro.xlf index e169d7ea2..e2ac4d989 100644 --- a/translations/messages.ro.xlf +++ b/translations/messages.ro.xlf @@ -86,14 +86,6 @@ user_profile Profilul meu - - api_token - Parola API - - - api_token_repeat - Reintrodu parola API - login_required Permisiuni insuficiente. Să te redirecționez la pagina de login? @@ -1590,10 +1582,6 @@ api_token_hidden Aceasta este singura dată când această cheie va fi afișată vreodată! Așa că păstrați-l în siguranță și asigurați-vă că ați copiat-o înainte de a închide această fereastră. - - api_password_deprecated - Parolele API sunt învechite: vă rugăm să utilizați în schimb jetoane API. - status.planned Planificat diff --git a/translations/messages.ru.xlf b/translations/messages.ru.xlf index 9ccb0cd0a..954c4e307 100644 --- a/translations/messages.ru.xlf +++ b/translations/messages.ru.xlf @@ -46,14 +46,6 @@ user_profile Мой профиль - - api_token - Пароль API - - - api_token_repeat - Повторите пароль API - menu.homepage Информпанель @@ -1790,10 +1782,6 @@ unlock_month.help Это разблокирует все дни года после выбранной даты. - - api_password_deprecated - Пароли API устарели: вместо них используйте токены API. - work_days Рабочие дни diff --git a/translations/messages.sk.xlf b/translations/messages.sk.xlf index 069951f81..9b37259b9 100644 --- a/translations/messages.sk.xlf +++ b/translations/messages.sk.xlf @@ -74,14 +74,6 @@ user_profile Môj profil - - api_token - API heslo - - - api_token_repeat - Zopakujte API heslo - login_required Nedostatočné oprávnenia. Presmerovať na prihlásenie? diff --git a/translations/messages.sl.xlf b/translations/messages.sl.xlf index 0b46f4d33..08881ba1e 100644 --- a/translations/messages.sl.xlf +++ b/translations/messages.sl.xlf @@ -142,10 +142,6 @@ user_profile Moj profil - - api_token - Geslo za API - login_required Manjka dovoljenje. Preusmeri na prijavo? @@ -398,10 +394,6 @@ created_at Ustvarjeno ob - - api_token_repeat - Ponovite geslo za API - error.no_comments_found Objavljenih komentarjev še ni bilo. diff --git a/translations/messages.sv.xlf b/translations/messages.sv.xlf index 7d02d72e1..4b48a5fd3 100644 --- a/translations/messages.sv.xlf +++ b/translations/messages.sv.xlf @@ -62,14 +62,6 @@ user_profile Min profil - - api_token - API lösenord - - - api_token_repeat - Upprepa API lösenord - menu.homepage Överblick @@ -1642,10 +1634,6 @@ api_token_hidden Detta är den enda gången nyckeln visas, så kopiera undan den till en säker plats innan du stänger fönstret. - - api_password_deprecated - API-lösenord är förlegade, använd API-nycklar istället. - Deactivate Inaktivera diff --git a/translations/messages.ta.xlf b/translations/messages.ta.xlf index 5bbf64b88..f7d392b0a 100644 --- a/translations/messages.ta.xlf +++ b/translations/messages.ta.xlf @@ -518,14 +518,6 @@ user_profile தன்விவரக்குறிப்பு - - api_token - பநிஇ கடவுச்சொல் - - - api_token_repeat - பநிஇ கடவுச்சொல்லை மீண்டும் இடு - login_required இசைவு இல்லை. திருப்பி உள்நுழை? @@ -1722,10 +1714,6 @@ api_token_hidden இந்த விசை காண்பிக்கப்படும் ஒரே நேரம் இதுதான்! எனவே அதைப் பாதுகாப்பாக வைத்திருங்கள், இந்தச் சாளரத்தை மூடுவதற்கு முன்பு நீங்கள் அதை நகலெடுத்துள்ளீர்கள் என்பதை உறுதிப்படுத்திக் கொள். - - api_password_deprecated - பநிஇ கடவுச்சொற்கள் காலாவதியானவை: அதற்குப் பதிலாக பநிஇ கிள்ளாக்குகளைப் பயன்படுத்து. - hours_per_day நாளைக்கு மணிநேரம் diff --git a/translations/messages.tr.xlf b/translations/messages.tr.xlf index ee931da5d..c9021ba6d 100644 --- a/translations/messages.tr.xlf +++ b/translations/messages.tr.xlf @@ -66,14 +66,6 @@ user_profile Profilim - - api_token - API parolası - - - api_token_repeat - API parolasını tekrarla - login_required İzin gerekli. Oturum açma sayfasına gidilsin mi? @@ -1646,10 +1638,6 @@ api_token_hidden Bu anahtarı bundan sonra görüntüleyemeyeceksiniz! Bu yüzden onu güvende tutun ve bu pencereyi kapatmadan önce kopyaladığınızdan emin olun. - - api_password_deprecated - API parolaları artık kullanılmıyor: lütfen bunun yerine API belirteçlerini kullanın. - Deactivate Devre dışı bırak diff --git a/translations/messages.uk.xlf b/translations/messages.uk.xlf index 37ead5cc5..61dd5ea67 100644 --- a/translations/messages.uk.xlf +++ b/translations/messages.uk.xlf @@ -106,14 +106,6 @@ user_profile Мій профіль - - api_token - Пароль API - - - api_token_repeat - Повторіть пароль API - login_required Відсутній дозвіл. Перенаправити на вхід? @@ -1642,10 +1634,6 @@ Last usage Останнє використання - - api_password_deprecated - Паролі API застаріли: будь ласка, використовуйте токени API. - hours_per_day Годин на день diff --git a/translations/messages.vi.xlf b/translations/messages.vi.xlf index 73ccc3e4d..e56e90bbc 100644 --- a/translations/messages.vi.xlf +++ b/translations/messages.vi.xlf @@ -86,14 +86,6 @@ user_profile Thông tin của tôi - - api_token - Mật khẩu API - - - api_token_repeat - Lặp lại mật khẩu API - login_required Thiếu sự cho phép. Chuyển hướng để đăng nhập? @@ -1646,10 +1638,6 @@ Expiry date Ngày hết hạn - - api_password_deprecated - Mật khẩu API đã lỗi thời: xin dùng mã API thay vào đó. - stop Dừng diff --git a/translations/messages.zh_CN.xlf b/translations/messages.zh_CN.xlf index 5a7287a19..2aeec4b87 100644 --- a/translations/messages.zh_CN.xlf +++ b/translations/messages.zh_CN.xlf @@ -70,14 +70,6 @@ user_profile 我的资料 - - api_token - API密码 - - - api_token_repeat - 再次输入API密码 - login_required 未许可。重新登录? @@ -1650,10 +1642,6 @@ api_token_hidden 这是该密码唯一一次显示! 因此,请确保其安全,并确保在关闭此窗口之前已将其复制下来。 - - api_password_deprecated - API 密码已过期:请改用 API 令牌。 - Activity number 活跃次数 diff --git a/translations/messages.zh_Hant.xlf b/translations/messages.zh_Hant.xlf index 616219dfc..a2e20aeb2 100644 --- a/translations/messages.zh_Hant.xlf +++ b/translations/messages.zh_Hant.xlf @@ -130,14 +130,6 @@ user_profile 我的資訊 - - api_token - API 密碼 - - - api_token_repeat - 再次輸入 API 密碼 - login_required 權限不足。要移至登入頁面嗎? @@ -1650,10 +1642,6 @@ user_identifier 使用者 ID - - api_password_deprecated - API 密碼已過時:請改用 API token。 - absence_comment_mandatory 缺勤:備註欄是必填欄位 diff --git a/webpack.config.js b/webpack.config.js index 85aad9050..ad6dd5510 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,13 +1,25 @@ -// Hint: if something doesn't work as expected: yarn upgrade --latest - const Encore = require('@symfony/webpack-encore'); -Encore - .setOutputPath('public/build/') - .setPublicPath('/build/') - .setManifestKeyPrefix('build/') - .cleanupOutputBeforeBuild() +// Manually configure the runtime environment if not already configured yet by the "encore" command. +// It's useful when you use tools that rely on webpack.config.js file. +if (!Encore.isRuntimeEnvironmentConfigured()) { + Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'prod'); +} +Encore + // directory where compiled assets will be stored + .setOutputPath('public/build/') + // public path used by the web server to access the output path + .setPublicPath('/build') + // only needed for CDN's or subdirectory deploy + //.setManifestKeyPrefix('build/') + + /* + * ENTRY CONFIG + * + * Each entry will result in one JavaScript file (e.g. app.js) + * and one CSS file (e.g. app.css) if your JavaScript imports CSS. + */ .addEntry('app', './assets/app.js') .addEntry('app-rtl', './assets/app-rtl.js') .addEntry('export-pdf', './assets/export-pdf.js') @@ -17,16 +29,38 @@ Encore .addEntry('calendar', './assets/calendar.js') .addEntry('highlight', './assets/highlight.js') + // When enabled, Webpack "splits" your files into smaller pieces for greater optimization. .splitEntryChunks() + + // will require an extra script tag for runtime.js + // but, you probably want this, unless you're building a single-page app + .enableSingleRuntimeChunk() + + /* + * FEATURE CONFIG + * + * Enable & configure other features below. For a full + * list of features, see: + * https://symfony.com/doc/current/frontend.html#adding-more-features + */ + .cleanupOutputBeforeBuild() + + // Displays build status system notifications to the user + // .enableBuildNotifications() + + .enableSourceMaps(!Encore.isProduction()) + // enables hashed filenames (e.g. app.abc123.css) + .enableVersioning(Encore.isProduction()) + .configureSplitChunks((splitChunks) => { splitChunks.chunks = 'async'; }) - .enableSingleRuntimeChunk() .configureBabel((config) => { config.sourceType = 'unambiguous'; config.plugins.push('@babel/plugin-syntax-dynamic-import'); }) + .configureBabelPresetEnv((config) => { config.useBuiltIns = 'usage'; config.corejs = 3; @@ -35,8 +69,6 @@ Encore }) .enableIntegrityHashes(Encore.isProduction()) - .enableVersioning(Encore.isProduction()) - .enableSourceMaps(!Encore.isProduction()) .enableSassLoader((options) => {}) .configureCssMinimizerPlugin((options) => { diff --git a/yarn.lock b/yarn.lock index c1fa75634..d1b08a168 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2542,6 +2542,15 @@ __metadata: languageName: node linkType: hard +"baseline-browser-mapping@npm:^2.9.0": + version: 2.9.11 + resolution: "baseline-browser-mapping@npm:2.9.11" + bin: + baseline-browser-mapping: dist/cli.js + checksum: 10/d71fe6693f999ee0bf1fcd72b31c01390f2bfac40d179175817f24cdb11b19d14a102227a8fa28e0a4733a17c780458c17384c75f2227e45b0e8a0080caf6532 + languageName: node + linkType: hard + "big.js@npm:^5.2.2": version: 5.2.2 resolution: "big.js@npm:5.2.2" @@ -2630,7 +2639,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.26.3, browserslist@npm:^4.28.0": +"browserslist@npm:^4.28.0": version: 4.28.0 resolution: "browserslist@npm:4.28.0" dependencies: @@ -2645,6 +2654,21 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.28.1": + version: 4.28.1 + resolution: "browserslist@npm:4.28.1" + dependencies: + baseline-browser-mapping: "npm:^2.9.0" + caniuse-lite: "npm:^1.0.30001759" + electron-to-chromium: "npm:^1.5.263" + node-releases: "npm:^2.0.27" + update-browserslist-db: "npm:^1.2.0" + bin: + browserslist: cli.js + checksum: 10/64f2a97de4bce8473c0e5ae0af8d76d1ead07a5b05fc6bc87b848678bb9c3a91ae787b27aa98cdd33fc00779607e6c156000bed58fefb9cf8e4c5a183b994cdb + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -2704,6 +2728,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001759": + version: 1.0.30001761 + resolution: "caniuse-lite@npm:1.0.30001761" + checksum: 10/9ebcef209a08d7c2f3d55b5105fafe48f657b3259a8cdd5842c5445aca9dcb0b6778cae524bde0cd73de508c680222edea594e64954503cbffd992407dbceda2 + languageName: node + linkType: hard + "chalk@npm:^2.3.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -3273,6 +3304,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.263": + version: 1.5.267 + resolution: "electron-to-chromium@npm:1.5.267" + checksum: 10/05e55e810cb6a3cda8d29dfdeec7ac0e59727a77a796a157f1a1d65edac16d45eed69ed5c99e354872ab16c48967c2d0a0600653051ae380a3b7a4d6210b1e60 + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.5.41": version: 1.5.52 resolution: "electron-to-chromium@npm:1.5.52" @@ -3303,13 +3341,13 @@ __metadata: languageName: node linkType: hard -"enhanced-resolve@npm:^5.17.3": - version: 5.18.3 - resolution: "enhanced-resolve@npm:5.18.3" +"enhanced-resolve@npm:^5.17.4": + version: 5.18.4 + resolution: "enhanced-resolve@npm:5.18.4" dependencies: graceful-fs: "npm:^4.2.4" tapable: "npm:^2.2.0" - checksum: 10/a4d0a1eacba3079f617b68c8f7e17583c3cbc572055c2edca41c0fa0230a49f6e9b2c6ffd4128cc5f84e15ea6cc313ae2b01e1057fcd252fabef70220a5d9f6a + checksum: 10/dcd477cb694d9cc84109a03269c13d3da0851d50099fd3fa7c56b2867dd720d59c7f1431bd47c9cad2825ad52588bd71d3a68cf1e5ee0bc57551d8a3fab4e6f2 languageName: node linkType: hard @@ -3359,10 +3397,10 @@ __metadata: languageName: node linkType: hard -"es-module-lexer@npm:^1.2.1": - version: 1.5.0 - resolution: "es-module-lexer@npm:1.5.0" - checksum: 10/d0e198d8642cb42aa82d86f2c6830cb6786916171a3e693046c11500c0cb62e77703940e58757db8aafa8a86fa2a9cc1c493dcd22c0b03c4a72dede3ce5c7dd1 +"es-module-lexer@npm:^2.0.0": + version: 2.0.0 + resolution: "es-module-lexer@npm:2.0.0" + checksum: 10/b075855289b5f40ee496f3d7525c5c501d029c3da15c22298a0030d625bf36d1da0768b26278f7f4bada2a602459b505888e20b77c414fba5da5619b0e84dbd1 languageName: node linkType: hard @@ -3766,6 +3804,13 @@ __metadata: languageName: node linkType: hard +"gridstack@npm:^7": + version: 7.3.0 + resolution: "gridstack@npm:7.3.0" + checksum: 10/125339be00976d6d4acc709f2b3486f5a01bbf8fb90042e9a7325117f101cebcb5b12fbbc339aae6c4285a54c7e7118b865267fb586476eef81a02c40596ad69 + languageName: node + linkType: hard + "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" @@ -3796,7 +3841,7 @@ __metadata: languageName: node linkType: hard -"highlight.js@npm:^11.11.1": +"highlight.js@npm:^11": version: 11.11.1 resolution: "highlight.js@npm:11.11.1" checksum: 10/205272f12f2c8ab1760452a75c58b043b11129cf3a5d2a9c0c90d43993580d0f5c385a73a4b8aba197eef20c0ec37d64000e6b35c4ed5991324f4c2dc78f4e43 @@ -4212,13 +4257,14 @@ __metadata: core-js: "npm:^3" eslint: "npm:^9" globals: "npm:^15" - highlight.js: "npm:^11.11.1" + gridstack: "npm:^7" + highlight.js: "npm:^11" litepicker: "npm:^2" luxon: "npm:^3" sass: "npm:^1" sass-loader: "npm:^16" - sortablejs: "npm:^1.15.6" - tom-select: "npm:^2.4.3" + sortablejs: "npm:^1.15" + tom-select: "npm:^2" webpack: "npm:^5" webpack-cli: "npm:^5" languageName: unknown @@ -5745,7 +5791,7 @@ __metadata: languageName: node linkType: hard -"sortablejs@npm:^1.15.6": +"sortablejs@npm:^1.15": version: 1.15.6 resolution: "sortablejs@npm:1.15.6" checksum: 10/3179071352662e6cff20d7d10792a934fc892a83a01ae09c7e604d2dd51daaf07283b00a8f2b13025f27959ff68a1469959bc94ef2a7049723d4c381a368a5ac @@ -5964,9 +6010,9 @@ __metadata: languageName: node linkType: hard -"terser-webpack-plugin@npm:^5.3.11": - version: 5.3.14 - resolution: "terser-webpack-plugin@npm:5.3.14" +"terser-webpack-plugin@npm:^5.3.16": + version: 5.3.16 + resolution: "terser-webpack-plugin@npm:5.3.16" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.25" jest-worker: "npm:^27.4.5" @@ -5982,7 +6028,7 @@ __metadata: optional: true uglify-js: optional: true - checksum: 10/5b7290f7edb179b83cefb8827c12371ddddc088cf251cf58a1c738d82628331ae6604273b61fe991d77411d4bb6b7178c3826aa47edf01b4ee21f973d6c8b8fb + checksum: 10/09dfbff602acfa114cdd174254b69a04adbc47856021ab351e37982202fd1ec85e0b62ffd5864c98beb8e96aef2f43da490b3448b4541db539c2cff6607394a6 languageName: node linkType: hard @@ -6037,7 +6083,7 @@ __metadata: languageName: node linkType: hard -"tom-select@npm:^2.4.3": +"tom-select@npm:^2": version: 2.4.3 resolution: "tom-select@npm:2.4.3" dependencies: @@ -6161,6 +6207,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.2.0": + version: 1.2.3 + resolution: "update-browserslist-db@npm:1.2.3" + dependencies: + escalade: "npm:^3.2.0" + picocolors: "npm:^1.1.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/059f774300efb4b084a49293143c511f3ae946d40397b5c30914e900cd5691a12b8e61b41dd54ed73d3b56c8204165a0333107dd784ccf8f8c81790bcc423175 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -6266,8 +6326,8 @@ __metadata: linkType: hard "webpack@npm:^5": - version: 5.103.0 - resolution: "webpack@npm:5.103.0" + version: 5.104.1 + resolution: "webpack@npm:5.104.1" dependencies: "@types/eslint-scope": "npm:^3.7.7" "@types/estree": "npm:^1.0.8" @@ -6277,10 +6337,10 @@ __metadata: "@webassemblyjs/wasm-parser": "npm:^1.14.1" acorn: "npm:^8.15.0" acorn-import-phases: "npm:^1.0.3" - browserslist: "npm:^4.26.3" + browserslist: "npm:^4.28.1" chrome-trace-event: "npm:^1.0.2" - enhanced-resolve: "npm:^5.17.3" - es-module-lexer: "npm:^1.2.1" + enhanced-resolve: "npm:^5.17.4" + es-module-lexer: "npm:^2.0.0" eslint-scope: "npm:5.1.1" events: "npm:^3.2.0" glob-to-regexp: "npm:^0.4.1" @@ -6291,7 +6351,7 @@ __metadata: neo-async: "npm:^2.6.2" schema-utils: "npm:^4.3.3" tapable: "npm:^2.3.0" - terser-webpack-plugin: "npm:^5.3.11" + terser-webpack-plugin: "npm:^5.3.16" watchpack: "npm:^2.4.4" webpack-sources: "npm:^3.3.3" peerDependenciesMeta: @@ -6299,7 +6359,7 @@ __metadata: optional: true bin: webpack: bin/webpack.js - checksum: 10/0018e77d159da412aa8cc1c3ac1d7c0b44228d0f5ce3939b4f424c04feba69747d8490541bcf8143b358a64afbbd69daad95e573ec9c4a90a99bef55d51dd43e + checksum: 10/c22b58fdf41d993971516154cb621d13b7b61dd744b7e2c6be972e9afcc9942694a8aaa322c07fba46448c69d663023ff53d0aeeb00eb0b125d83ace5ca8fa3c languageName: node linkType: hard