Release 2.0.34 (#4281)
This commit is contained in:
@@ -21,9 +21,9 @@ now requires the `charset` and `serverVersion` params, e.g.: `DATABASE_URL=mysql
|
||||
|
||||
- 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
|
||||
- dashboard default config
|
||||
- removed: theme.branding.translation
|
||||
- removed: kimai.plugin_dir
|
||||
- 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
|
||||
|
||||
|
||||
@@ -440,8 +440,14 @@ export default class KimaiCalendar {
|
||||
calendarSource = {...calendarSource, ...{
|
||||
id: 'kimai-' + source.id,
|
||||
events: (fetchInfo, successCallback, failureCallback) => {
|
||||
let url = source.url.replace('{from}', DATES.formatForAPI(fetchInfo.start));
|
||||
url = url.replace('{to}', DATES.formatForAPI(fetchInfo.end));
|
||||
const targetFrom = DATES.formatForAPI(fetchInfo.start);
|
||||
const targetTo = DATES.formatForAPI(fetchInfo.end);
|
||||
|
||||
let url = source.url;
|
||||
url = url.replace('{from}', targetFrom);
|
||||
url = url.replace('__FROM__', targetFrom);
|
||||
url = url.replace('{to}', targetTo);
|
||||
url = url.replace('__TO__', targetTo);
|
||||
|
||||
API.get(url, {}, result => {
|
||||
let apiEvents = [];
|
||||
@@ -463,8 +469,14 @@ export default class KimaiCalendar {
|
||||
id: 'json-' + source.id,
|
||||
editable: false,
|
||||
events: (fetchInfo, successCallback, failureCallback) => {
|
||||
let url = source.url.replace('{from}', DATES.formatForAPI(fetchInfo.start));
|
||||
url = url.replace('{to}', DATES.formatForAPI(fetchInfo.end));
|
||||
const targetFrom = DATES.formatForAPI(fetchInfo.start);
|
||||
const targetTo = DATES.formatForAPI(fetchInfo.end);
|
||||
|
||||
let url = source.url;
|
||||
url = url.replace('{from}', targetFrom);
|
||||
url = url.replace('__FROM__', targetFrom);
|
||||
url = url.replace('{to}', targetTo);
|
||||
url = url.replace('__TO__', targetTo);
|
||||
|
||||
API.get(url, {}, result => {
|
||||
let apiEvents = [];
|
||||
|
||||
@@ -179,7 +179,13 @@
|
||||
"tests-unit": "vendor/bin/phpunit --exclude-group integration tests/",
|
||||
"tests-integration": "vendor/bin/phpunit --group integration tests/",
|
||||
"phpstan": [
|
||||
"vendor/bin/phpstan analyse -c phpstan.neon",
|
||||
"@phpstan-src",
|
||||
"@phpstan-tests"
|
||||
],
|
||||
"phpstan-src": [
|
||||
"vendor/bin/phpstan analyse -c phpstan.neon"
|
||||
],
|
||||
"phpstan-tests": [
|
||||
"vendor/bin/phpstan analyse -c tests/phpstan.neon"
|
||||
],
|
||||
"codestyle": "vendor/bin/php-cs-fixer fix --dry-run --verbose --show-progress=none",
|
||||
|
||||
441
composer.lock
generated
441
composer.lock
generated
File diff suppressed because it is too large
Load Diff
232
phpstan.neon
232
phpstan.neon
@@ -1221,11 +1221,6 @@ parameters:
|
||||
count: 3
|
||||
path: src/Controller/Reporting/ProjectDateRangeController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\ProjectDateRangeController\\:\\:__invoke\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/Reporting/ProjectDateRangeController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$begin of method App\\\\Form\\\\Model\\\\DateRange\\:\\:setBegin\\(\\) expects DateTime, DateTime\\|null given\\.$#"
|
||||
count: 1
|
||||
@@ -1241,31 +1236,16 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/Reporting/ProjectDateRangeController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\ProjectDetailsController\\:\\:__invoke\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/Reporting/ProjectDetailsController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getId\\(\\) on App\\\\Entity\\\\Customer\\|null\\.$#"
|
||||
count: 3
|
||||
path: src/Controller/Reporting/ProjectInactiveController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\ProjectInactiveController\\:\\:__invoke\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/Reporting/ProjectInactiveController.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method getId\\(\\) on App\\\\Entity\\\\Customer\\|null\\.$#"
|
||||
count: 3
|
||||
path: src/Controller/Reporting/ProjectViewController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\ProjectViewController\\:\\:__invoke\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/Reporting/ProjectViewController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\ReportUsersMonthController\\:\\:getData\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -1591,11 +1571,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Activity.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Activity\\:\\:addTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Activity.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Activity\\:\\:getMetaFields\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
@@ -1606,11 +1581,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Activity.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Activity\\:\\:removeTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Activity.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$name of method App\\\\Entity\\\\Activity\\:\\:getMetaField\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
@@ -1651,36 +1621,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Bookmark.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\CommentInterface\\:\\:setCreatedAt\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/CommentInterface.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\CommentInterface\\:\\:setCreatedBy\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/CommentInterface.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\CommentInterface\\:\\:setMessage\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/CommentInterface.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\CommentInterface\\:\\:setPinned\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/CommentInterface.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Customer\\:\\:__toString\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Customer.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Customer\\:\\:addTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Customer.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Customer\\:\\:getMetaFields\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
@@ -1691,11 +1636,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Customer.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Customer\\:\\:removeTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Customer.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$name of method App\\\\Entity\\\\Customer\\:\\:getMetaField\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
@@ -1766,11 +1706,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Project.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Project\\:\\:addTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Project.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Project\\:\\:getMetaFields\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
@@ -1781,16 +1716,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/Project.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Project\\:\\:localizeDates\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Project.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\Project\\:\\:removeTeam\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/Project.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$name of method App\\\\Entity\\\\Project\\:\\:getMetaField\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
@@ -1926,31 +1851,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method hasUser\\(\\) on App\\\\Entity\\\\Team\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Cannot call method removeMember\\(\\) on App\\\\Entity\\\\Team\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:__toString\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:__unserialize\\(\\) has parameter \\$data with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:addRole\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:getFirstDayOfWeek\\(\\) should return string but returns bool\\|float\\|int\\|string\\|null\\.$#"
|
||||
count: 1
|
||||
@@ -1966,11 +1871,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:getName\\(\\) should return string but returns string\\|null\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:getPreferences\\(\\) return type with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
@@ -2011,11 +1911,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:setLanguage\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:setPassword\\(\\) has parameter \\$password with no type specified\\.$#"
|
||||
count: 1
|
||||
@@ -2026,51 +1921,16 @@ parameters:
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:setPreferenceValue\\(\\) has no return 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
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Entity\\\\User\\:\\:setTimezone\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$haystack of function mb_strstr expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$secret of class Scheb\\\\TwoFactorBundle\\\\Model\\\\Totp\\\\TotpConfiguration constructor expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function mb_strlen expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$string of function mb_substr expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$string of function explode expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Entity/User.php
|
||||
|
||||
-
|
||||
message: "#^Property App\\\\Entity\\\\User\\:\\:\\$memberships with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
@@ -2463,7 +2323,7 @@ parameters:
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$filename of method App\\\\Export\\\\ExportFilename\\:\\:convert\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 2
|
||||
count: 1
|
||||
path: src/Export/ExportFilename.php
|
||||
|
||||
-
|
||||
@@ -6720,93 +6580,3 @@ parameters:
|
||||
message: "#^Method App\\\\Form\\\\MultiUpdate\\\\MultiUpdateTableDTO\\:\\:setEntities\\(\\) has parameter \\$entities with generic interface Doctrine\\\\Common\\\\Collections\\\\Collection but does not specify its types\\: TKey, T$#"
|
||||
count: 1
|
||||
path: src/Form/MultiUpdate/MultiUpdateTableDTO.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\MarkdownExtension', 'commentContent'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\MarkdownExtension', 'commentOneLiner'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\MarkdownExtension', 'markdownToHtml'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\MarkdownExtension', 'timesheetContent'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'colorize'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFilter constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'KevinPapst\\\\\\\\TablerBundle\\\\\\\\Twig\\\\\\\\RuntimeExtension', 'icon'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\EncoreExtension', 'getEncoreEntryCssSo…'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\QrCodeExtension', 'qrCodeDataUriFuncti…'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'actions'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'generateTitle'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'getJavascriptTransl…'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'getProgressbarClass'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'getTimePresets'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\ThemeExtension', 'trigger'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\TimesheetExtension', 'activeEntries'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\TimesheetExtension', 'favoriteEntries'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'App\\\\\\\\Twig\\\\\\\\Runtime\\\\\\\\WidgetExtension', 'renderWidget'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$callable of class Twig\\\\TwigFunction constructor expects array\\<class\\-string, string\\>\\|\\(callable\\(\\)\\: mixed\\)\\|null, array\\{'KevinPapst\\\\\\\\TablerBundle\\\\\\\\Twig\\\\\\\\RuntimeExtension', 'createIcon'\\} given\\.$#"
|
||||
count: 1
|
||||
path: src/Twig/RuntimeExtensions.php
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -45,7 +45,7 @@
|
||||
"calendar": {
|
||||
"js": [
|
||||
"/build/runtime.f0079159.js",
|
||||
"/build/calendar.ea514f59.js"
|
||||
"/build/calendar.3f4f78fe.js"
|
||||
],
|
||||
"css": [
|
||||
"/build/calendar.bb473428.css"
|
||||
@@ -72,7 +72,7 @@
|
||||
"/build/invoice-pdf.ce9aace0.js": "sha384-mtZkXrpsXFMX2YvmmTlCm91QgsTlZLzLJnDAFcTuBDtDZ7TNkqLYkfCeLzFLVfwb",
|
||||
"/build/invoice-pdf.2b749265.css": "sha384-DXXgkz2WWnrWnfBnXX5fmfPQSPb98upMnWxYKwTGYS04EhrPIWfDCutB2unIrWh7",
|
||||
"/build/chart.f5becfac.js": "sha384-GSqETm8wULiVXyizvwRompfwu63r/C0Qd/AvrHDE4cqAKiIGCssb3QyBtGu1WN+W",
|
||||
"/build/calendar.ea514f59.js": "sha384-s162N0JRCI0twVtDROON8kABO+riWgiXM7O6TA175IOkAh94twcLqKoAfycd2BrA",
|
||||
"/build/calendar.3f4f78fe.js": "sha384-RD8enOf0Foe7IhSOGnv2DCes4QUCvLjlONH0HFq3RK9l/ozrFZakTX6SWwKOoEda",
|
||||
"/build/calendar.bb473428.css": "sha384-900W9o8666Qpw21rLP7hn5Ql8tWd40k0IcE3QpFm7E7V6bKva7xQgGlyzVuuh4GK",
|
||||
"/build/dashboard.6774a712.js": "sha384-lBwkNqUPv+IBbznagiFakY2BOIueq/Bg89wHO2XeM9YAZ51rPkrvdMd+XmFupHsM",
|
||||
"/build/dashboard.18f5a8b7.css": "sha384-PBD8ftb2yBoSjRe2sN5Xb4dEz045kOEUfcIufdSis+tWoWdAx5j4Yic+F/6CYbrP"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"build/invoice-pdf.js": "/build/invoice-pdf.ce9aace0.js",
|
||||
"build/chart.js": "/build/chart.f5becfac.js",
|
||||
"build/calendar.css": "/build/calendar.bb473428.css",
|
||||
"build/calendar.js": "/build/calendar.ea514f59.js",
|
||||
"build/calendar.js": "/build/calendar.3f4f78fe.js",
|
||||
"build/dashboard.css": "/build/dashboard.18f5a8b7.css",
|
||||
"build/dashboard.js": "/build/dashboard.6774a712.js",
|
||||
"build/runtime.js": "/build/runtime.f0079159.js"
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.33';
|
||||
public const VERSION = '2.0.34';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20033;
|
||||
public const VERSION_ID = 20034;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -68,6 +68,7 @@ final class ContractController extends AbstractController
|
||||
$page = new PageSetup('work_times');
|
||||
$page->setHelp('contract.html');
|
||||
$page->setActionName('contract');
|
||||
$page->setActionPayload(['profile' => $profile, 'year' => $yearDate]);
|
||||
$page->setPaginationForm($form);
|
||||
|
||||
// additional boxes by plugins
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Reporting\ProjectDateRange\ProjectDateRangeForm;
|
||||
use App\Reporting\ProjectDateRange\ProjectDateRangeQuery;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -24,7 +25,7 @@ final class ProjectDateRangeController extends AbstractController
|
||||
#[Route(path: '/reporting/project_daterange', name: 'report_project_daterange', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('report:project')]
|
||||
#[IsGranted(new Expression("is_granted('budget_any', 'project')"))]
|
||||
public function __invoke(Request $request, ProjectStatisticService $service)
|
||||
public function __invoke(Request $request, ProjectStatisticService $service): Response
|
||||
{
|
||||
$dateFactory = $this->getDateTimeFactory();
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -16,6 +16,7 @@ use App\Reporting\ProjectDetails\ProjectDetailsQuery;
|
||||
use App\Utils\PageSetup;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -24,7 +25,7 @@ final class ProjectDetailsController extends AbstractController
|
||||
#[Route(path: '/reporting/project_details', name: 'report_project_details', methods: ['GET'])]
|
||||
#[IsGranted('report:project')]
|
||||
#[IsGranted(new Expression("is_granted('details', 'project')"))]
|
||||
public function __invoke(Request $request, ProjectStatisticService $service)
|
||||
public function __invoke(Request $request, ProjectStatisticService $service): Response
|
||||
{
|
||||
$dateFactory = $this->getDateTimeFactory();
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Reporting\ProjectInactive\ProjectInactiveForm;
|
||||
use App\Reporting\ProjectInactive\ProjectInactiveQuery;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -23,7 +24,7 @@ final class ProjectInactiveController extends AbstractController
|
||||
#[Route(path: '/reporting/project_inactive', name: 'report_project_inactive', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('report:project')]
|
||||
#[IsGranted(new Expression("is_granted('budget_any', 'project')"))]
|
||||
public function __invoke(Request $request, ProjectStatisticService $service)
|
||||
public function __invoke(Request $request, ProjectStatisticService $service): Response
|
||||
{
|
||||
$dateFactory = $this->getDateTimeFactory();
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -15,6 +15,7 @@ use App\Reporting\ProjectView\ProjectViewForm;
|
||||
use App\Reporting\ProjectView\ProjectViewQuery;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Annotation\Route;
|
||||
use Symfony\Component\Security\Http\Attribute\IsGranted;
|
||||
|
||||
@@ -23,7 +24,7 @@ final class ProjectViewController extends AbstractController
|
||||
#[Route(path: '/reporting/project_view', name: 'report_project_view', methods: ['GET', 'POST'])]
|
||||
#[IsGranted('report:project')]
|
||||
#[IsGranted(new Expression("is_granted('budget_any', 'project')"))]
|
||||
public function __invoke(Request $request, ProjectStatisticService $service)
|
||||
public function __invoke(Request $request, ProjectStatisticService $service): Response
|
||||
{
|
||||
$dateFactory = $this->getDateTimeFactory();
|
||||
$user = $this->getUser();
|
||||
|
||||
@@ -232,7 +232,7 @@ class Activity implements EntityWithMetaFields, EntityWithBudget
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addTeam(Team $team)
|
||||
public function addTeam(Team $team): void
|
||||
{
|
||||
if ($this->teams->contains($team)) {
|
||||
return;
|
||||
@@ -242,7 +242,7 @@ class Activity implements EntityWithMetaFields, EntityWithBudget
|
||||
$team->addActivity($this);
|
||||
}
|
||||
|
||||
public function removeTeam(Team $team)
|
||||
public function removeTeam(Team $team): void
|
||||
{
|
||||
if (!$this->teams->contains($team)) {
|
||||
return;
|
||||
|
||||
@@ -15,17 +15,17 @@ interface CommentInterface
|
||||
|
||||
public function getMessage(): ?string;
|
||||
|
||||
public function setMessage(string $message);
|
||||
public function setMessage(string $message): void;
|
||||
|
||||
public function getCreatedBy(): ?User;
|
||||
|
||||
public function setCreatedBy(User $createdBy);
|
||||
public function setCreatedBy(User $createdBy): void;
|
||||
|
||||
public function getCreatedAt(): ?\DateTime;
|
||||
|
||||
public function setCreatedAt(\DateTime $createdAt);
|
||||
public function setCreatedAt(\DateTime $createdAt): void;
|
||||
|
||||
public function isPinned(): bool;
|
||||
|
||||
public function setPinned(bool $pinned);
|
||||
public function setPinned(bool $pinned): void;
|
||||
}
|
||||
|
||||
@@ -440,7 +440,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addTeam(Team $team)
|
||||
public function addTeam(Team $team): void
|
||||
{
|
||||
if ($this->teams->contains($team)) {
|
||||
return;
|
||||
@@ -450,7 +450,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget
|
||||
$team->addCustomer($this);
|
||||
}
|
||||
|
||||
public function removeTeam(Team $team)
|
||||
public function removeTeam(Team $team): void
|
||||
{
|
||||
if (!$this->teams->contains($team)) {
|
||||
return;
|
||||
|
||||
@@ -253,7 +253,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
|
||||
* Make sure begin and end date have the correct timezone.
|
||||
* This will be called once for each item after being loaded from the database.
|
||||
*/
|
||||
protected function localizeDates()
|
||||
protected function localizeDates(): void
|
||||
{
|
||||
if ($this->localized) {
|
||||
return;
|
||||
@@ -392,7 +392,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addTeam(Team $team)
|
||||
public function addTeam(Team $team): void
|
||||
{
|
||||
if ($this->teams->contains($team)) {
|
||||
return;
|
||||
@@ -402,7 +402,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
|
||||
$team->addProject($this);
|
||||
}
|
||||
|
||||
public function removeTeam(Team $team)
|
||||
public function removeTeam(Team $team): void
|
||||
{
|
||||
if (!$this->teams->contains($team)) {
|
||||
return;
|
||||
|
||||
@@ -371,7 +371,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
* @param string $name
|
||||
* @param bool|int|string|float|null $value
|
||||
*/
|
||||
public function setPreferenceValue(string $name, $value = null)
|
||||
public function setPreferenceValue(string $name, $value = null): void
|
||||
{
|
||||
$pref = $this->getPreference($name);
|
||||
|
||||
@@ -421,7 +421,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return $this->getLocale();
|
||||
}
|
||||
|
||||
public function setLanguage(?string $language)
|
||||
public function setLanguage(?string $language): void
|
||||
{
|
||||
if ($language === null) {
|
||||
$language = User::DEFAULT_LANGUAGE;
|
||||
@@ -449,7 +449,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return (string) $this->getPreferenceValue(UserPreference::SKIN, 'default', false);
|
||||
}
|
||||
|
||||
public function setTimezone(?string $timezone)
|
||||
public function setTimezone(?string $timezone): void
|
||||
{
|
||||
if ($timezone === null) {
|
||||
$timezone = date_default_timezone_get();
|
||||
@@ -536,7 +536,9 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
}
|
||||
|
||||
$this->memberships->removeElement($member);
|
||||
$member->getTeam()->removeMember($member);
|
||||
if ($member->getTeam() !== null) {
|
||||
$member->getTeam()->removeMember($member);
|
||||
}
|
||||
$member->setUser(null);
|
||||
$member->setTeam(null);
|
||||
}
|
||||
@@ -590,7 +592,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
public function hasTeamMember(User $user): bool
|
||||
{
|
||||
foreach ($this->memberships as $membership) {
|
||||
if ($membership->getTeam()->hasUser($user)) {
|
||||
if ($membership->getTeam() !== null && $membership->getTeam()->hasUser($user)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -598,6 +600,34 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this function to check if the current user can read data from the given user.
|
||||
*/
|
||||
public function canSeeUser(User $user): bool
|
||||
{
|
||||
if ($user->getId() === $this->getId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->canSeeAllData()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$user->isEnabled()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->isSystemAccount() && $user->isSystemAccount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isTeamleadOfUser($user)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of all teams, this user is part of
|
||||
*
|
||||
@@ -673,6 +703,17 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isTeamleadOfUser(User $user): bool
|
||||
{
|
||||
foreach ($this->memberships as $membership) {
|
||||
if ($membership->isTeamlead() && $membership->getTeam() !== null && $membership->getTeam()->hasUser($user)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function canSeeAllData(): bool
|
||||
{
|
||||
return $this->isSuperAdmin() || true === $this->isAllowedToSeeAllData;
|
||||
@@ -708,7 +749,7 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return $this->hasRole(static::ROLE_ADMIN);
|
||||
}
|
||||
|
||||
public function getDisplayName(): ?string
|
||||
public function getDisplayName(): string
|
||||
{
|
||||
if (!empty($this->getAlias())) {
|
||||
return $this->getAlias();
|
||||
@@ -744,18 +785,16 @@ class User implements UserInterface, EquatableInterface, ThemeUserInterface, Pas
|
||||
return $this->auth === null || $this->auth === self::AUTH_INTERNAL;
|
||||
}
|
||||
|
||||
public function addRole(string $role)
|
||||
public function addRole(string $role): void
|
||||
{
|
||||
$role = strtoupper($role);
|
||||
if ($role === static::DEFAULT_ROLE) {
|
||||
return $this;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!\in_array($role, $this->roles, true)) {
|
||||
$this->roles[] = $role;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void
|
||||
|
||||
@@ -16,6 +16,8 @@ use App\Repository\UserRepository;
|
||||
use App\Utils\Color;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\Form\FormView;
|
||||
use Symfony\Component\OptionsResolver\Options;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
@@ -65,10 +67,6 @@ final class UserType extends AbstractType
|
||||
'type' => 'integer',
|
||||
'description' => 'User ID',
|
||||
],
|
||||
'attr' => [
|
||||
'data-select-attributes' => 'color,title,username,initials,accountNumber,alias',
|
||||
'data-renderer' => 'color',
|
||||
],
|
||||
]);
|
||||
|
||||
$resolver->setDefault('query_builder', function (Options $options) {
|
||||
@@ -93,6 +91,14 @@ final class UserType extends AbstractType
|
||||
});
|
||||
}
|
||||
|
||||
public function buildView(FormView $view, FormInterface $form, array $options): void
|
||||
{
|
||||
$view->vars['attr'] = array_merge($view->vars['attr'], [
|
||||
'data-select-attributes' => 'color,title,username,initials,accountNumber,alias',
|
||||
'data-renderer' => 'color',
|
||||
]);
|
||||
}
|
||||
|
||||
public function getParent(): string
|
||||
{
|
||||
return EntityType::class;
|
||||
|
||||
@@ -92,7 +92,7 @@ final class InvoiceItemDefaultHydrator implements InvoiceItemHydrator
|
||||
'entry.user_name' => $user->getUserIdentifier(),
|
||||
'entry.user_title' => $user->getTitle() ?? '',
|
||||
'entry.user_alias' => $user->getAlias() ?? '',
|
||||
'entry.user_display' => $user->getDisplayName() ?? '',
|
||||
'entry.user_display' => $user->getDisplayName(),
|
||||
]);
|
||||
|
||||
foreach ($user->getVisiblePreferences() as $pref) {
|
||||
|
||||
@@ -27,7 +27,7 @@ final class InvoiceModelUserHydrator implements InvoiceModelHydrator
|
||||
'user.email' => $user->getEmail(),
|
||||
'user.title' => $user->getTitle() ?? '',
|
||||
'user.alias' => $user->getAlias() ?? '',
|
||||
'user.display' => $user->getDisplayName() ?? '',
|
||||
'user.display' => $user->getDisplayName(),
|
||||
];
|
||||
|
||||
foreach ($user->getPreferences() as $metaField) {
|
||||
|
||||
@@ -19,13 +19,13 @@ final class Pagination extends Pagerfanta
|
||||
{
|
||||
parent::__construct($adapter);
|
||||
|
||||
if ($query === null || !$query->isApiCall()) {
|
||||
$this->setNormalizeOutOfRangePages(true);
|
||||
}
|
||||
|
||||
if ($query !== null) {
|
||||
$this->setMaxPerPage($query->getPageSize());
|
||||
$this->setCurrentPage($query->getPage());
|
||||
}
|
||||
|
||||
if ($query === null || !$query->isApiCall()) {
|
||||
$this->setNormalizeOutOfRangePages(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ use Symfony\Component\Security\Core\Authorization\Voter\Voter;
|
||||
final class UserVoter extends Voter
|
||||
{
|
||||
private const ALLOWED_ATTRIBUTES = [
|
||||
'access_user',
|
||||
'view',
|
||||
'edit',
|
||||
'roles',
|
||||
@@ -62,10 +63,18 @@ final class UserVoter extends Voter
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!($subject instanceof User)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($attribute === 'contract') {
|
||||
return $this->permissionManager->hasRolePermission($user, 'contract_other_profile');
|
||||
}
|
||||
|
||||
if ($attribute === 'access_user') {
|
||||
return $user->canSeeUser($subject);
|
||||
}
|
||||
|
||||
if ($attribute === 'view_team_member') {
|
||||
if ($subject->getId() !== $user->getId()) {
|
||||
return false;
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% block box_body %}
|
||||
{{ form_start(form) }}
|
||||
{{ form_widget(form) }}
|
||||
{% if form.user is defined %}
|
||||
{{ form_row(form.user) }}
|
||||
{% endif %}
|
||||
{{ form_rest(form) }}
|
||||
{{ form_end(form) }}
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
@@ -132,7 +135,7 @@
|
||||
{
|
||||
id: 'kimaiUserTimeSource',
|
||||
type: 'timesheet',
|
||||
url: '{{ path('get_timesheets') }}?user={{ user.id }}&size=1000&full=true&begin={from}&end={to}',
|
||||
url: '{{ path('get_timesheets', {'user': user.id, 'size': 1000, 'full': 'true', 'begin': '__FROM__', 'end': '__TO__'})|raw }}',
|
||||
options: {
|
||||
color: '{{ config('theme.calendar.background_color') }}',
|
||||
},
|
||||
@@ -157,7 +160,7 @@
|
||||
{
|
||||
id: '{{ source.id }}{{ loop.index }}',
|
||||
type: '{{ source.typeName }}',
|
||||
url: '{{ source.uri }}',
|
||||
url: '{{ source.uri|raw }}',
|
||||
options: {...{{ source.options|json_encode|raw }}, ...{
|
||||
color: '{{ source.color }}',
|
||||
textColor: '{{ source.color|font_contrast }}',
|
||||
|
||||
@@ -253,7 +253,7 @@
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% if (route is not empty and entries is not null) or multi_update_form is not null%}
|
||||
{% if (route is not empty and entries is not null) or multi_update_form is not null %}
|
||||
<div class="card-footer d-flex align-items-center">
|
||||
{% if multi_update_form is not null %}
|
||||
{{ form_start(multi_update_form, {'attr': {'id': 'multi_update_form', 'style': 'display:none', 'data-question': 'update_multiple'|trans}}) }}
|
||||
|
||||
@@ -246,7 +246,7 @@
|
||||
|
||||
{% macro alert(type, description, title, icon, dismissible) %}
|
||||
{% from '@theme/components/alert.html.twig' import alert %}
|
||||
{{ alert({type: type, description: description|trans, title: title|trans, icon: icon, dismissible: dismissible}) }}
|
||||
{{ alert({type: type, description: description|trans, title: title|trans, icon: icon, dismissible: dismissible, important: true}) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro callout(type, description, title, icon) %}
|
||||
|
||||
@@ -287,7 +287,7 @@ abstract class APIControllerBaseTest extends ControllerBaseTest
|
||||
foreach ($messages as $i => $message) {
|
||||
self::assertEquals($message, $data[$fieldName]['errors'][$i]);
|
||||
}
|
||||
if (\array_key_exists('errors', $data[$fieldName]) && \count($data[$fieldName]['errors']) > 0) {
|
||||
if (\array_key_exists('errors', (array) $data[$fieldName]) && \count($data[$fieldName]['errors']) > 0) {
|
||||
$foundErrors[$fieldName] = \count($data[$fieldName]['errors']);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user