diff --git a/composer.json b/composer.json
index e4e3706f..2d1193a6 100644
--- a/composer.json
+++ b/composer.json
@@ -16,6 +16,7 @@
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
+ "ext-xml": "*",
"ext-xsl": "*",
"ext-zip": "*",
"beberlei/doctrineextensions": "^1.2",
diff --git a/composer.lock b/composer.lock
index 9f61dfb2..e43d9fa7 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "1b9dd5a62d735ab920ce887fd95e2913",
+ "content-hash": "e49b6d7813734f458c32176aa129f251",
"packages": [
{
"name": "beberlei/doctrineextensions",
@@ -1404,16 +1404,16 @@
},
{
"name": "doctrine/persistence",
- "version": "2.5.2",
+ "version": "2.5.3",
"source": {
"type": "git",
"url": "https://github.com/doctrine/persistence.git",
- "reference": "4276c6cbc0ca692c190f650a2678623bf04af2d2"
+ "reference": "d7edf274b6d35ad82328e223439cc2bb2f92bd9e"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/doctrine/persistence/zipball/4276c6cbc0ca692c190f650a2678623bf04af2d2",
- "reference": "4276c6cbc0ca692c190f650a2678623bf04af2d2",
+ "url": "https://api.github.com/repos/doctrine/persistence/zipball/d7edf274b6d35ad82328e223439cc2bb2f92bd9e",
+ "reference": "d7edf274b6d35ad82328e223439cc2bb2f92bd9e",
"shasum": ""
},
"require": {
@@ -1486,7 +1486,7 @@
],
"support": {
"issues": "https://github.com/doctrine/persistence/issues",
- "source": "https://github.com/doctrine/persistence/tree/2.5.2"
+ "source": "https://github.com/doctrine/persistence/tree/2.5.3"
},
"funding": [
{
@@ -1502,7 +1502,7 @@
"type": "tidelift"
}
],
- "time": "2022-05-02T17:29:02+00:00"
+ "time": "2022-05-03T09:16:53+00:00"
},
{
"name": "doctrine/sql-formatter",
@@ -1770,16 +1770,16 @@
},
{
"name": "friendsofphp/proxy-manager-lts",
- "version": "v1.0.11",
+ "version": "v1.0.12",
"source": {
"type": "git",
"url": "https://github.com/FriendsOfPHP/proxy-manager-lts.git",
- "reference": "d1eadf86d5b843c496614ef075a8f655a880f1d8"
+ "reference": "8419f0158715b30d4b99a5bd37c6a39671994ad7"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/d1eadf86d5b843c496614ef075a8f655a880f1d8",
- "reference": "d1eadf86d5b843c496614ef075a8f655a880f1d8",
+ "url": "https://api.github.com/repos/FriendsOfPHP/proxy-manager-lts/zipball/8419f0158715b30d4b99a5bd37c6a39671994ad7",
+ "reference": "8419f0158715b30d4b99a5bd37c6a39671994ad7",
"shasum": ""
},
"require": {
@@ -1836,7 +1836,7 @@
],
"support": {
"issues": "https://github.com/FriendsOfPHP/proxy-manager-lts/issues",
- "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.11"
+ "source": "https://github.com/FriendsOfPHP/proxy-manager-lts/tree/v1.0.12"
},
"funding": [
{
@@ -1848,7 +1848,7 @@
"type": "tidelift"
}
],
- "time": "2022-05-04T11:03:58+00:00"
+ "time": "2022-05-05T09:31:05+00:00"
},
{
"name": "friendsofsymfony/rest-bundle",
@@ -4201,16 +4201,16 @@
},
{
"name": "phpstan/phpdoc-parser",
- "version": "1.5.0",
+ "version": "1.5.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
- "reference": "6cafed9212aa56aaa3aaf3b67c0fd1e5de53f50c"
+ "reference": "981cc368a216c988e862a75e526b6076987d1b50"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/6cafed9212aa56aaa3aaf3b67c0fd1e5de53f50c",
- "reference": "6cafed9212aa56aaa3aaf3b67c0fd1e5de53f50c",
+ "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/981cc368a216c988e862a75e526b6076987d1b50",
+ "reference": "981cc368a216c988e862a75e526b6076987d1b50",
"shasum": ""
},
"require": {
@@ -4239,9 +4239,9 @@
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
- "source": "https://github.com/phpstan/phpdoc-parser/tree/1.5.0"
+ "source": "https://github.com/phpstan/phpdoc-parser/tree/1.5.1"
},
- "time": "2022-05-04T07:46:54+00:00"
+ "time": "2022-05-05T11:32:40+00:00"
},
{
"name": "psr/cache",
@@ -11852,16 +11852,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.6.5",
+ "version": "1.6.7",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "462f7651f3454f280d6a397be3290634ab937022"
+ "reference": "d41c39cb2e487663bce9bbd97c660e244b73abad"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/462f7651f3454f280d6a397be3290634ab937022",
- "reference": "462f7651f3454f280d6a397be3290634ab937022",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/d41c39cb2e487663bce9bbd97c660e244b73abad",
+ "reference": "d41c39cb2e487663bce9bbd97c660e244b73abad",
"shasum": ""
},
"require": {
@@ -11887,7 +11887,7 @@
"description": "PHPStan - PHP Static Analysis Tool",
"support": {
"issues": "https://github.com/phpstan/phpstan/issues",
- "source": "https://github.com/phpstan/phpstan/tree/1.6.5"
+ "source": "https://github.com/phpstan/phpstan/tree/1.6.7"
},
"funding": [
{
@@ -11907,7 +11907,7 @@
"type": "tidelift"
}
],
- "time": "2022-05-04T10:49:26+00:00"
+ "time": "2022-05-04T22:55:41+00:00"
},
{
"name": "phpstan/phpstan-doctrine",
@@ -14077,6 +14077,7 @@
"ext-json": "*",
"ext-mbstring": "*",
"ext-pdo": "*",
+ "ext-xml": "*",
"ext-xsl": "*",
"ext-zip": "*"
},
diff --git a/config/packages/kimai.yaml b/config/packages/kimai.yaml
index 42703db2..d3ba4d08 100644
--- a/config/packages/kimai.yaml
+++ b/config/packages/kimai.yaml
@@ -37,7 +37,7 @@ kimai:
# mode: default
# The default time to pre-fill the "create timesheet" form (in some cases).
- # This setting is only respected by some timetracking modes and not in all situations.
+ # This setting is only respected by some time-tracking modes and not in all situations.
#
# Accepted formats, see
# - https://www.php.net/manual/en/datetime.formats.php
@@ -244,6 +244,10 @@ kimai:
date: 'Y-m-d'
date_time: 'm-d H:i'
duration: '%%h:%%m h'
+ en_GB:
+ date_type: 'dd/MM/yyyy'
+ date: 'd-m-Y'
+ date_time: 'd-m H:i'
es:
date_type: 'dd.MM.yyyy'
date: 'd.m.Y'
@@ -275,6 +279,10 @@ kimai:
date: 'd.m.Y'
date_time: 'd.m. H:i'
duration: '%%hu%%m'
+ pt:
+ date_type: 'dd/MM/yyyy'
+ date: 'd/m/Y'
+ date_time: 'd-m H:i'
pt_BR:
date_type: 'dd-MM-yyyy'
date: 'd-m-Y'
diff --git a/config/services.yaml b/config/services.yaml
index 41993017..8c006e82 100644
--- a/config/services.yaml
+++ b/config/services.yaml
@@ -2,7 +2,7 @@
# https://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
parameters:
locale: en
- app_locales: ar|cs|da|de|de_AT|de_CH|el|en|eo|es|eu|fa|fi|fo|fr|he|hr|hu|it|ja|ko|nb_NO|nl|pl|pt|pt_BR|ro|ru|sk|sv|tr|vi|zh_CN
+ app_locales: ar|cs|da|de|de_AT|de_CH|el|en|en_GB|eo|es|eu|fa|fi|fo|fr|he|hr|hu|it|ja|ko|nb_NO|nl|pl|pt|pt_BR|ro|ru|sk|sv|tr|vi|zh_CN
services:
# default configuration for services in *this* file
diff --git a/src/Constants.php b/src/Constants.php
index 8f5902f6..30992226 100644
--- a/src/Constants.php
+++ b/src/Constants.php
@@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
- public const VERSION = '1.19.7';
+ public const VERSION = '1.19.8';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
- public const VERSION_ID = 11907;
+ public const VERSION_ID = 11908;
/**
* The current release status, either "stable" or "dev"
*/
diff --git a/src/Controller/DoctorController.php b/src/Controller/DoctorController.php
index bc84740a..a2f7f74a 100644
--- a/src/Controller/DoctorController.php
+++ b/src/Controller/DoctorController.php
@@ -29,13 +29,14 @@ class DoctorController extends AbstractController
* Some are not a hard requiremenet, but some functions might not work as expected.
*/
public const REQUIRED_EXTENSIONS = [
+ 'gd',
'intl',
'json',
'mbstring',
'pdo',
+ 'xml',
+ 'xsl',
'zip',
- 'gd',
- 'xml'
];
/**
diff --git a/src/Controller/QuickEntryController.php b/src/Controller/QuickEntryController.php
index 727f970f..20cd6f72 100644
--- a/src/Controller/QuickEntryController.php
+++ b/src/Controller/QuickEntryController.php
@@ -99,7 +99,13 @@ class QuickEntryController extends AbstractController
// attach recent activities
$amount = $this->configuration->getQuickEntriesRecentAmount();
- $timesheets = $this->repository->getRecentActivities($this->getUser(), null, $amount);
+ $startFrom = null;
+ $takeOverWeeks = $this->configuration->find('quick_entry.recent_activity_weeks');
+ if ($takeOverWeeks !== null && \intval($takeOverWeeks) > 0) {
+ $startFrom = clone $startWeek;
+ $startFrom->modify(sprintf('-%s weeks', $takeOverWeeks));
+ }
+ $timesheets = $this->repository->getRecentActivities($this->getUser(), $startFrom, $amount);
foreach ($timesheets as $timesheet) {
$id = $timesheet->getProject()->getId() . '_' . $timesheet->getActivity()->getId();
if (\array_key_exists($id, $rows)) {
@@ -145,7 +151,7 @@ class QuickEntryController extends AbstractController
}
// add empty rows for simpler starting
- $minRows = 3;
+ $minRows = \intval($this->configuration->find('quick_entry.minimum_rows'));
if (\count($models) < $minRows) {
$newRows = $minRows - \count($models);
for ($a = 0; $a < $newRows; $a++) {
diff --git a/src/Controller/SystemConfigurationController.php b/src/Controller/SystemConfigurationController.php
index 0d26fd07..9251a9d8 100644
--- a/src/Controller/SystemConfigurationController.php
+++ b/src/Controller/SystemConfigurationController.php
@@ -42,6 +42,7 @@ use Symfony\Component\Form\Extension\Core\Type\CountryType;
use Symfony\Component\Form\Extension\Core\Type\CurrencyType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
+use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -114,7 +115,7 @@ final class SystemConfigurationController extends AbstractController
$configurations[] = [
'model' => $configModel,
- 'form' => $this->createConfigurationsForm($configModel)->createView(),
+ 'form' => $this->createConfigurationsForm($configModel, true)->createView(),
];
}
@@ -124,13 +125,14 @@ final class SystemConfigurationController extends AbstractController
}
/**
- * @Route(path="/update/{section}", name="system_configuration_update", methods={"POST"})
+ * @Route(path="/update/{section}/{single}", name="system_configuration_update", methods={"POST"})
*
+ * @internal do not link directly to this route
* @param Request $request
* @param string $section
* @return \Symfony\Component\HttpFoundation\RedirectResponse|\Symfony\Component\HttpFoundation\Response
*/
- public function configUpdate(Request $request, string $section)
+ public function configUpdate(Request $request, string $section, bool $single)
{
$configModel = null;
$configSettings = $this->getInitializedConfigurations();
@@ -145,7 +147,7 @@ final class SystemConfigurationController extends AbstractController
throw $this->createNotFoundException('Could not find config model: ' . $section);
}
- $form = $this->createConfigurationsForm($configModel);
+ $form = $this->createConfigurationsForm($configModel, $single);
$form->handleRequest($request);
if ($form->isSubmitted()) {
@@ -157,6 +159,10 @@ final class SystemConfigurationController extends AbstractController
$this->flashUpdateException($ex);
}
+ if ($single) {
+ return $this->redirectToRoute('system_configuration_section', ['section' => $section]);
+ }
+
return $this->redirectToRoute('system_configuration');
} else {
$this->flashError('action.update.error', ['%reason%' => 'Validation problem']);
@@ -167,8 +173,12 @@ final class SystemConfigurationController extends AbstractController
$configurations = [];
foreach ($configSettings as $configModel) {
+ if ($single && $section !== $configModel->getSection()) {
+ continue;
+ }
+
if ($section !== $configModel->getSection()) {
- $form2 = $this->createConfigurationsForm($configModel);
+ $form2 = $this->createConfigurationsForm($configModel, $single);
} else {
$form2 = $form;
}
@@ -183,14 +193,10 @@ final class SystemConfigurationController extends AbstractController
]);
}
- /**
- * @param SystemConfigurationModel $configuration
- * @return \Symfony\Component\Form\FormInterface
- */
- private function createConfigurationsForm(SystemConfigurationModel $configuration)
+ private function createConfigurationsForm(SystemConfigurationModel $configuration, bool $isSingleSection = false): FormInterface
{
$options = [
- 'action' => $this->generateUrl('system_configuration_update', ['section' => $configuration->getSection()]),
+ 'action' => $this->generateUrl('system_configuration_update', ['section' => $configuration->getSection(), 'single' => $isSingleSection ? '1' : '0']),
'method' => 'POST',
];
@@ -401,6 +407,21 @@ final class SystemConfigurationController extends AbstractController
->setConstraints([
new Range(['min' => 0, 'max' => 20]),
]),
+ (new Configuration())
+ ->setName('quick_entry.recent_activity_weeks')
+ ->setType(IntegerType::class)
+ ->setTranslationDomain('system-configuration')
+ ->setRequired(false)
+ ->setConstraints([
+ new Range(['min' => 0, 'max' => 20]),
+ ]),
+ (new Configuration())
+ ->setName('quick_entry.minimum_rows')
+ ->setType(IntegerType::class)
+ ->setTranslationDomain('system-configuration')
+ ->setConstraints([
+ new Range(['min' => 1, 'max' => 5]),
+ ]),
]),
(new SystemConfigurationModel('lockdown_period'))
->setConfiguration([
diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php
index a6e632ba..d6f6e33c 100644
--- a/src/DependencyInjection/Configuration.php
+++ b/src/DependencyInjection/Configuration.php
@@ -88,6 +88,12 @@ class Configuration implements ConfigurationInterface
->integerNode('recent_activities')
->defaultValue(5)
->end()
+ ->integerNode('recent_activity_weeks')
+ ->defaultNull()
+ ->end()
+ ->integerNode('minimum_rows')
+ ->defaultValue(3)
+ ->end()
->end()
;
diff --git a/tests/Controller/SystemConfigurationControllerTest.php b/tests/Controller/SystemConfigurationControllerTest.php
index 418005af..7cdf7044 100644
--- a/tests/Controller/SystemConfigurationControllerTest.php
+++ b/tests/Controller/SystemConfigurationControllerTest.php
@@ -69,19 +69,19 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
public function getTestDataForms()
{
return [
- ['form[name=system_configuration_form_timesheet]', $this->createUrl('/admin/system-config/update/timesheet')],
- ['form[name=system_configuration_form_quick_entry]', $this->createUrl('/admin/system-config/update/quick_entry')],
- ['form[name=system_configuration_form_lockdown_period]', $this->createUrl('/admin/system-config/update/lockdown_period')],
- ['form[name=system_configuration_form_invoice]', $this->createUrl('/admin/system-config/update/invoice')],
- ['form[name=system_configuration_form_authentication]', $this->createUrl('/admin/system-config/update/authentication')],
- ['form[name=system_configuration_form_rounding]', $this->createUrl('/admin/system-config/update/rounding')],
- ['form[name=system_configuration_form_customer]', $this->createUrl('/admin/system-config/update/customer')],
- ['form[name=system_configuration_form_project]', $this->createUrl('/admin/system-config/update/project')],
- ['form[name=system_configuration_form_activity]', $this->createUrl('/admin/system-config/update/activity')],
- ['form[name=system_configuration_form_user]', $this->createUrl('/admin/system-config/update/user')],
- ['form[name=system_configuration_form_theme]', $this->createUrl('/admin/system-config/update/theme')],
- ['form[name=system_configuration_form_calendar]', $this->createUrl('/admin/system-config/update/calendar')],
- ['form[name=system_configuration_form_branding]', $this->createUrl('/admin/system-config/update/branding')],
+ ['form[name=system_configuration_form_timesheet]', $this->createUrl('/admin/system-config/update/timesheet/0')],
+ ['form[name=system_configuration_form_quick_entry]', $this->createUrl('/admin/system-config/update/quick_entry/0')],
+ ['form[name=system_configuration_form_lockdown_period]', $this->createUrl('/admin/system-config/update/lockdown_period/0')],
+ ['form[name=system_configuration_form_invoice]', $this->createUrl('/admin/system-config/update/invoice/0')],
+ ['form[name=system_configuration_form_authentication]', $this->createUrl('/admin/system-config/update/authentication/0')],
+ ['form[name=system_configuration_form_rounding]', $this->createUrl('/admin/system-config/update/rounding/0')],
+ ['form[name=system_configuration_form_customer]', $this->createUrl('/admin/system-config/update/customer/0')],
+ ['form[name=system_configuration_form_project]', $this->createUrl('/admin/system-config/update/project/0')],
+ ['form[name=system_configuration_form_activity]', $this->createUrl('/admin/system-config/update/activity/0')],
+ ['form[name=system_configuration_form_user]', $this->createUrl('/admin/system-config/update/user/0')],
+ ['form[name=system_configuration_form_theme]', $this->createUrl('/admin/system-config/update/theme/0')],
+ ['form[name=system_configuration_form_calendar]', $this->createUrl('/admin/system-config/update/calendar/0')],
+ ['form[name=system_configuration_form_branding]', $this->createUrl('/admin/system-config/update/branding/0')],
];
}
@@ -220,7 +220,7 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
public function testUpdateUserConfig()
{
$client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN);
- $this->assertAccessIsGranted($client, '/admin/system-config/');
+ $this->assertAccessIsGranted($client, '/admin/system-config/edit/user');
$configService = static::$kernel->getContainer()->get(SystemConfiguration::class);
$this->assertNull($configService->find('defaults.user.timezone'));
@@ -238,7 +238,7 @@ class SystemConfigurationControllerTest extends ControllerBaseTest
]
]);
- $this->assertIsRedirect($client, $this->createUrl('/admin/system-config/'));
+ $this->assertIsRedirect($client, $this->createUrl('/admin/system-config/edit/user'));
$client->followRedirect();
$this->assertTrue($client->getResponse()->isSuccessful());
$this->assertHasFlashSaveSuccess($client);
diff --git a/tests/DependencyInjection/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php
index eda2a615..e751f218 100644
--- a/tests/DependencyInjection/ConfigurationTest.php
+++ b/tests/DependencyInjection/ConfigurationTest.php
@@ -463,7 +463,9 @@ class ConfigurationTest extends TestCase
'financial_year' => null,
],
'quick_entry' => [
- 'recent_activities' => 5
+ 'recent_activities' => 5,
+ 'recent_activity_weeks' => null,
+ 'minimum_rows' => 3,
],
];
diff --git a/translations/system-configuration.de.xlf b/translations/system-configuration.de.xlf
index f6d514f5..a5dcec13 100644
--- a/translations/system-configuration.de.xlf
+++ b/translations/system-configuration.de.xlf
@@ -90,6 +90,14 @@
label.quick_entry.recent_activities
Anzahl übernommener Einträge aus Vorwochen
+
+ label.quick_entry.recent_activity_weeks
+ Verwende Einträge aus den letzten X Wochen (leer oder 0 für gesamte Zeit)
+
+
+ label.quick_entry.minimum_rows
+ Minimale Anzahl an Zeilen
+
label.theme.autocomplete_chars
Minimale Anzahl Buchstaben für den Start der Autovervollständigung
diff --git a/translations/system-configuration.en.xlf b/translations/system-configuration.en.xlf
index 6da63d24..5052cbff 100644
--- a/translations/system-configuration.en.xlf
+++ b/translations/system-configuration.en.xlf
@@ -90,6 +90,14 @@
label.quick_entry.recent_activities
Number of entries taken over from previous weeks
+
+ label.quick_entry.recent_activity_weeks
+ Take over entries from the last X weeks (empty or 0 for all time)
+
+
+ label.quick_entry.minimum_rows
+ Minimum number of rows
+
label.theme.autocomplete_chars
Minimum number of letters to start auto-completion