diff --git a/src/Controller/SystemConfigurationController.php b/src/Controller/SystemConfigurationController.php index af015f4a..f07a26fd 100644 --- a/src/Controller/SystemConfigurationController.php +++ b/src/Controller/SystemConfigurationController.php @@ -14,12 +14,15 @@ use App\Event\SystemConfigurationEvent; use App\Form\Model\Configuration; use App\Form\Model\SystemConfiguration as SystemConfigurationModel; use App\Form\SystemConfigurationForm; +use App\Form\Type\ActivityTypePatternType; use App\Form\Type\ArrayToCommaStringType; +use App\Form\Type\CustomerTypePatternType; use App\Form\Type\DatePickerType; use App\Form\Type\DateTimeTextType; use App\Form\Type\DayTimeType; use App\Form\Type\LanguageType; use App\Form\Type\MinuteIncrementType; +use App\Form\Type\ProjectTypePatternType; use App\Form\Type\RoundingModeType; use App\Form\Type\SkinType; use App\Form\Type\TimezoneType; @@ -496,6 +499,24 @@ final class SystemConfigurationController extends AbstractController ->setLabel('currency') ->setType(CurrencyType::class) ->setOptions(['help' => 'default_value_new']), + (new Configuration()) + ->setName('customer.choice_pattern') + ->setLabel('choice_pattern') + ->setType(CustomerTypePatternType::class), + ]), + (new SystemConfigurationModel('project')) + ->setConfiguration([ + (new Configuration()) + ->setName('project.choice_pattern') + ->setLabel('choice_pattern') + ->setType(ProjectTypePatternType::class), + ]), + (new SystemConfigurationModel('activity')) + ->setConfiguration([ + (new Configuration()) + ->setName('activity.choice_pattern') + ->setLabel('choice_pattern') + ->setType(ActivityTypePatternType::class), ]), (new SystemConfigurationModel('user')) ->setConfiguration([ diff --git a/src/EventSubscriber/Actions/ActivitiesSubscriber.php b/src/EventSubscriber/Actions/ActivitiesSubscriber.php index 7a0f0236..ca0a29ae 100644 --- a/src/EventSubscriber/Actions/ActivitiesSubscriber.php +++ b/src/EventSubscriber/Actions/ActivitiesSubscriber.php @@ -34,6 +34,10 @@ class ActivitiesSubscriber extends AbstractActionsSubscriber $event->addCreate($this->path('admin_activity_create')); } + if ($this->isGranted('system_configuration')) { + $event->addAction('settings', ['url' => $this->path('system_configuration_section', ['section' => 'activity']), 'class' => 'modal-ajax-form']); + } + $event->addHelp($this->documentationLink('activity.html')); } } diff --git a/src/EventSubscriber/Actions/CustomersSubscriber.php b/src/EventSubscriber/Actions/CustomersSubscriber.php index 8c3dace9..dd0c2bc5 100644 --- a/src/EventSubscriber/Actions/CustomersSubscriber.php +++ b/src/EventSubscriber/Actions/CustomersSubscriber.php @@ -34,6 +34,10 @@ class CustomersSubscriber extends AbstractActionsSubscriber $event->addCreate($this->path('admin_customer_create')); } + if ($this->isGranted('system_configuration')) { + $event->addAction('settings', ['url' => $this->path('system_configuration_section', ['section' => 'customer']), 'class' => 'modal-ajax-form']); + } + $event->addHelp($this->documentationLink('customer.html')); } } diff --git a/src/EventSubscriber/Actions/ProjectsSubscriber.php b/src/EventSubscriber/Actions/ProjectsSubscriber.php index d756cdc7..208f6088 100644 --- a/src/EventSubscriber/Actions/ProjectsSubscriber.php +++ b/src/EventSubscriber/Actions/ProjectsSubscriber.php @@ -35,6 +35,10 @@ class ProjectsSubscriber extends AbstractActionsSubscriber $event->addCreate($this->path('admin_project_create')); } + if ($this->isGranted('system_configuration')) { + $event->addAction('settings', ['url' => $this->path('system_configuration_section', ['section' => 'project']), 'class' => 'modal-ajax-form']); + } + $event->addHelp($this->documentationLink('project.html')); } } diff --git a/src/Form/Type/ActivityType.php b/src/Form/Type/ActivityType.php index 2c041a6c..df4838a3 100644 --- a/src/Form/Type/ActivityType.php +++ b/src/Form/Type/ActivityType.php @@ -9,6 +9,7 @@ namespace App\Form\Type; +use App\Configuration\SystemConfiguration; use App\Entity\Activity; use App\Repository\ActivityRepository; use App\Repository\Query\ActivityFormTypeQuery; @@ -22,6 +23,44 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ class ActivityType extends AbstractType { + public const PATTERN_NAME = '{name}'; + public const PATTERN_COMMENT = '{comment}'; + public const PATTERN_SPACER = '{spacer}'; + public const SPACER = ' - '; + + private $configuration; + private $pattern; + + public function __construct(SystemConfiguration $configuration) + { + $this->configuration = $configuration; + } + + public function getChoiceLabel(Activity $activity): string + { + if ($this->pattern === null) { + $this->pattern = $this->configuration->find('activity.choice_pattern'); + + if ($this->pattern === null || stripos($this->pattern, '{') === false || stripos($this->pattern, '}') === false) { + $this->pattern = self::PATTERN_NAME; + } + } + + $name = $this->pattern; + $name = str_replace(self::PATTERN_NAME, $activity->getName(), $name); + $name = str_replace(self::PATTERN_COMMENT, $activity->getComment(), $name); + $name = str_replace(self::PATTERN_SPACER, self::SPACER, $name); + + $name = ltrim($name, self::SPACER); + $name = rtrim($name, self::SPACER); + + if ($name === '' || $name === self::SPACER) { + $name = $activity->getName(); + } + + return $name; + } + /** * {@inheritdoc} */ @@ -35,32 +74,18 @@ class ActivityType extends AbstractType } /** - * {@inheritdoc} - */ - public function choiceLabel(Activity $activity) - { - return $activity->getName(); - } - - /** - * @param Activity $choiceValue + * @param Activity $activity * @param string $key * @param mixed $value * @return array */ - public function choiceAttr($choiceValue, $key, $value) + public function getChoiceAttributes(Activity $activity, $key, $value) { - $project = null; - - if (!($choiceValue instanceof Activity)) { - return []; + if (null !== ($project = $activity->getProject())) { + return ['data-project' => $project->getId(), 'data-currency' => $project->getCustomer()->getCurrency()]; } - if (null !== $choiceValue->getProject()) { - $project = $choiceValue->getProject()->getId(); - } - - return ['data-project' => $project]; + return []; } /** @@ -76,9 +101,9 @@ class ActivityType extends AbstractType ], 'label' => 'label.activity', 'class' => Activity::class, - 'choice_label' => [$this, 'choiceLabel'], + 'choice_label' => [$this, 'getChoiceLabel'], + 'choice_attr' => [$this, 'getChoiceAttributes'], 'group_by' => [$this, 'groupBy'], - 'choice_attr' => [$this, 'choiceAttr'], 'query_builder_for_user' => true, // @var Project|Project[]|int|int[]|null 'projects' => null, diff --git a/src/Form/Type/ActivityTypePatternType.php b/src/Form/Type/ActivityTypePatternType.php new file mode 100644 index 00000000..c5ad1fad --- /dev/null +++ b/src/Form/Type/ActivityTypePatternType.php @@ -0,0 +1,55 @@ +translator = $translator; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $name = $this->translator->trans('label.name'); + $comment = $this->translator->trans('label.description'); + $spacer = ActivityType::SPACER; + + $resolver->setDefaults([ + 'label' => 'label.choice_pattern', + 'choices' => [ + $name => ActivityType::PATTERN_NAME, + $comment => ActivityType::PATTERN_COMMENT, + $name . $spacer . $comment => ActivityType::PATTERN_NAME . ActivityType::PATTERN_SPACER . ActivityType::PATTERN_COMMENT, + ] + ]); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return ChoiceType::class; + } +} diff --git a/src/Form/Type/CustomerType.php b/src/Form/Type/CustomerType.php index 713687e9..cfeaa594 100644 --- a/src/Form/Type/CustomerType.php +++ b/src/Form/Type/CustomerType.php @@ -9,6 +9,7 @@ namespace App\Form\Type; +use App\Configuration\SystemConfiguration; use App\Entity\Customer; use App\Repository\CustomerRepository; use App\Repository\Query\CustomerFormTypeQuery; @@ -23,6 +24,53 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ class CustomerType extends AbstractType { + public const PATTERN_NAME = '{name}'; + public const PATTERN_NUMBER = '{number}'; + public const PATTERN_COMPANY = '{company}'; + public const PATTERN_COMMENT = '{comment}'; + public const PATTERN_SPACER = '{spacer}'; + public const SPACER = ' - '; + + private $configuration; + private $pattern; + + public function __construct(SystemConfiguration $configuration) + { + $this->configuration = $configuration; + } + + public function getChoiceLabel(Customer $customer): string + { + if ($this->pattern === null) { + $this->pattern = $this->configuration->find('customer.choice_pattern'); + + if ($this->pattern === null || stripos($this->pattern, '{') === false || stripos($this->pattern, '}') === false) { + $this->pattern = self::PATTERN_NAME; + } + } + + $name = $this->pattern; + $name = str_replace(self::PATTERN_NAME, $customer->getName(), $name); + $name = str_replace(self::PATTERN_COMMENT, $customer->getComment(), $name); + $name = str_replace(self::PATTERN_NUMBER, $customer->getNumber(), $name); + $name = str_replace(self::PATTERN_COMPANY, $customer->getCompany() ?? $customer->getName(), $name); + $name = str_replace(self::PATTERN_SPACER, self::SPACER, $name); + + $name = ltrim($name, self::SPACER); + $name = rtrim($name, self::SPACER); + + if ($name === '' || $name === self::SPACER) { + $name = $customer->getName(); + } + + return $name; + } + + public function getChoiceAttributes(Customer $customer, $key, $value): array + { + return ['data-currency' => $customer->getCurrency()]; + } + /** * {@inheritdoc} */ @@ -36,7 +84,8 @@ class CustomerType extends AbstractType ], 'label' => 'label.customer', 'class' => Customer::class, - 'choice_label' => 'name', + 'choice_label' => [$this, 'getChoiceLabel'], + 'choice_attr' => [$this, 'getChoiceAttributes'], 'query_builder_for_user' => true, 'project_enabled' => false, 'project_select' => 'project', diff --git a/src/Form/Type/CustomerTypePatternType.php b/src/Form/Type/CustomerTypePatternType.php new file mode 100644 index 00000000..7e1f3ad0 --- /dev/null +++ b/src/Form/Type/CustomerTypePatternType.php @@ -0,0 +1,65 @@ +translator = $translator; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $name = $this->translator->trans('label.name'); + $company = $this->translator->trans('label.company'); + $number = $this->translator->trans('label.number'); + $comment = $this->translator->trans('label.description'); + $spacer = CustomerType::SPACER; + + $resolver->setDefaults([ + 'label' => 'label.choice_pattern', + 'choices' => [ + $name => CustomerType::PATTERN_NAME, + $company => CustomerType::PATTERN_COMPANY, + $number => CustomerType::PATTERN_NUMBER, + $comment => CustomerType::PATTERN_COMMENT, + $name . $spacer . $company => CustomerType::PATTERN_NAME . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_COMPANY, + $name . $spacer . $number => CustomerType::PATTERN_NAME . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_NUMBER, + $name . $spacer . $comment => CustomerType::PATTERN_NAME . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_COMMENT, + $number . $spacer . $name => CustomerType::PATTERN_NUMBER . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_NAME, + $number . $spacer . $company => CustomerType::PATTERN_NUMBER . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_COMPANY, + $number . $spacer . $comment => CustomerType::PATTERN_NUMBER . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_COMMENT, + $company . $spacer . $comment => CustomerType::PATTERN_COMPANY . CustomerType::PATTERN_SPACER . CustomerType::PATTERN_COMMENT, + ] + ]); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return ChoiceType::class; + } +} diff --git a/src/Form/Type/ProjectType.php b/src/Form/Type/ProjectType.php index a70f173d..ce600484 100644 --- a/src/Form/Type/ProjectType.php +++ b/src/Form/Type/ProjectType.php @@ -9,10 +9,12 @@ namespace App\Form\Type; +use App\Configuration\SystemConfiguration; use App\Entity\Project; use App\Repository\ProjectRepository; use App\Repository\Query\ActivityQuery; use App\Repository\Query\ProjectFormTypeQuery; +use App\Utils\LocaleSettings; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractType; use Symfony\Component\OptionsResolver\Options; @@ -23,25 +25,93 @@ use Symfony\Component\OptionsResolver\OptionsResolver; */ class ProjectType extends AbstractType { + public const PATTERN_NAME = '{name}'; + public const PATTERN_COMMENT = '{comment}'; + public const PATTERN_ORDERNUMBER = '{ordernumber}'; + public const PATTERN_DATERANGE = '{daterange}'; + public const PATTERN_START = '{start}'; + public const PATTERN_END = '{end}'; + public const PATTERN_SPACER = '{spacer}'; + public const SPACER = ' - '; + + private $configuration; + private $localeSettings; + private $dateFormat; + private $pattern; + + public function __construct(SystemConfiguration $configuration, LocaleSettings $localeSettings) + { + $this->configuration = $configuration; + $this->localeSettings = $localeSettings; + } + + public function getChoiceLabel(Project $project): string + { + if ($this->dateFormat === null) { + $this->dateFormat = $this->localeSettings->getDateFormat(); + } + + if ($this->pattern === null) { + $this->pattern = $this->configuration->find('project.choice_pattern'); + + if ($this->pattern === null || stripos($this->pattern, '{') === false || stripos($this->pattern, '}') === false) { + $this->pattern = self::PATTERN_NAME; + } + } + + $dateRange = ''; + if ($project->getStart() !== null) { + $dateRange = self::PATTERN_START; + } + if ($project->getEnd() !== null) { + if ($dateRange !== '') { + $dateRange .= '-'; + } + $dateRange .= self::PATTERN_END; + } + + $start = ''; + if ($project->getStart() !== null) { + $start = $project->getStart()->format($this->dateFormat); + } + + $end = ''; + if ($project->getEnd() !== null) { + $end = $project->getEnd()->format($this->dateFormat); + } + + $name = $this->pattern; + $name = str_replace(self::PATTERN_NAME, $project->getName(), $name); + $name = str_replace(self::PATTERN_COMMENT, $project->getComment(), $name); + $name = str_replace(self::PATTERN_ORDERNUMBER, $project->getOrderNumber(), $name); + $name = str_replace(self::PATTERN_DATERANGE, $dateRange, $name); + $name = str_replace(self::PATTERN_START, $start, $name); + $name = str_replace(self::PATTERN_END, $end, $name); + $name = str_replace(self::PATTERN_SPACER, self::SPACER, $name); + + $name = ltrim($name, self::SPACER); + $name = rtrim($name, self::SPACER); + + if ($name === '' || $name === self::SPACER) { + $name = $project->getName(); + } + + return $name; + } + /** - * @param Project $choiceValue + * @param Project $project * @param string $key * @param mixed $value * @return array */ - public function choiceAttr($choiceValue, $key, $value) + public function getChoiceAttributes(Project $project, $key, $value): array { - $customer = null; - - if (!($choiceValue instanceof Project)) { - return []; + if (null !== ($customer = $project->getCustomer())) { + return ['data-customer' => $customer->getId(), 'data-currency' => $customer->getCurrency()]; } - if (null !== $choiceValue->getCustomer()) { - $customer = $choiceValue->getCustomer()->getId(); - } - - return ['data-customer' => $customer]; + return []; } /** @@ -57,8 +127,8 @@ class ProjectType extends AbstractType ], 'label' => 'label.project', 'class' => Project::class, - 'choice_label' => 'name', - 'choice_attr' => [$this, 'choiceAttr'], + 'choice_label' => [$this, 'getChoiceLabel'], + 'choice_attr' => [$this, 'getChoiceAttributes'], 'group_by' => function (Project $project, $key, $index) { return $project->getCustomer()->getName(); }, diff --git a/src/Form/Type/ProjectTypePatternType.php b/src/Form/Type/ProjectTypePatternType.php new file mode 100644 index 00000000..41cd1f90 --- /dev/null +++ b/src/Form/Type/ProjectTypePatternType.php @@ -0,0 +1,61 @@ +translator = $translator; + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $resolver) + { + $name = $this->translator->trans('label.name'); + $comment = $this->translator->trans('label.description'); + $orderNumber = $this->translator->trans('label.orderNumber'); + $projectStart = $this->translator->trans('label.project_start'); + $projectEnd = $this->translator->trans('label.project_end'); + + $spacer = ProjectType::SPACER; + + $resolver->setDefaults([ + 'label' => 'label.choice_pattern', + 'choices' => [ + $name => ProjectType::PATTERN_NAME, + $comment => ProjectType::PATTERN_COMMENT, + $name . $spacer . $orderNumber => ProjectType::PATTERN_NAME . ProjectType::PATTERN_SPACER . ProjectType::PATTERN_ORDERNUMBER, + $name . $spacer . $comment => ProjectType::PATTERN_NAME . ProjectType::PATTERN_SPACER . ProjectType::PATTERN_COMMENT, + $name . $spacer . $projectStart . '-' . $projectEnd => ProjectType::PATTERN_NAME . ProjectType::PATTERN_SPACER . ProjectType::PATTERN_DATERANGE, + ] + ]); + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return ChoiceType::class; + } +} diff --git a/src/Utils/LocaleSettings.php b/src/Utils/LocaleSettings.php index c68b2c78..dca605da 100644 --- a/src/Utils/LocaleSettings.php +++ b/src/Utils/LocaleSettings.php @@ -18,13 +18,27 @@ use Symfony\Component\HttpFoundation\RequestStack; */ final class LocaleSettings extends LocaleFormats { + private $requestStack; + private $locale; + public function __construct(RequestStack $requestStack, LanguageFormattings $formats) { - $locale = Constants::DEFAULT_LOCALE; - // request is null in a console command - if (null !== $requestStack->getMasterRequest()) { - $locale = $requestStack->getMasterRequest()->getLocale(); + parent::__construct($formats, Constants::DEFAULT_LOCALE); + $this->requestStack = $requestStack; + } + + public function getLocale(): string + { + if ($this->locale === null) { + $locale = \Locale::getDefault(); + + // request is null in a console command + if (null !== $this->requestStack->getMasterRequest()) { + $locale = $this->requestStack->getMasterRequest()->getLocale(); + } + $this->locale = $locale; } - parent::__construct($formats, $locale); + + return $this->locale; } } diff --git a/tests/Controller/ActivityControllerTest.php b/tests/Controller/ActivityControllerTest.php index 2080324d..f7b218dc 100644 --- a/tests/Controller/ActivityControllerTest.php +++ b/tests/Controller/ActivityControllerTest.php @@ -41,6 +41,30 @@ class ActivityControllerTest extends ControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $this->assertAccessIsGranted($client, '/admin/activity/'); $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/activity/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/activity/create'), + 'help' => 'https://www.kimai.org/documentation/activity.html' + ]); + } + + public function testIndexActionAsSuperAdmin() + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); + $this->assertAccessIsGranted($client, '/admin/activity/'); + $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/activity/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/activity/create'), + 'settings modal-ajax-form' => $this->createUrl('/admin/system-config/edit/activity'), + 'help' => 'https://www.kimai.org/documentation/activity.html' + ]); } public function testIndexActionWithSearchTermQuery() diff --git a/tests/Controller/CustomerControllerTest.php b/tests/Controller/CustomerControllerTest.php index 2c6f41f2..60c06052 100644 --- a/tests/Controller/CustomerControllerTest.php +++ b/tests/Controller/CustomerControllerTest.php @@ -43,6 +43,29 @@ class CustomerControllerTest extends ControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $this->assertAccessIsGranted($client, '/admin/customer/'); $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/customer/export'), + 'help' => 'https://www.kimai.org/documentation/customer.html' + ]); + } + + public function testIndexActionAsSuperAdmin() + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); + $this->assertAccessIsGranted($client, '/admin/customer/'); + $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/customer/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/customer/create'), + 'settings modal-ajax-form' => $this->createUrl('/admin/system-config/edit/customer'), + 'help' => 'https://www.kimai.org/documentation/customer.html' + ]); } public function testIndexActionWithSearchTermQuery() @@ -61,6 +84,14 @@ class CustomerControllerTest extends ControllerBaseTest $this->assertAccessIsGranted($client, '/admin/customer/'); + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/customer/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/customer/create'), + 'help' => 'https://www.kimai.org/documentation/customer.html' + ]); + $form = $client->getCrawler()->filter('form.searchform')->form(); $client->submit($form, [ 'searchTerm' => 'feature:timetracking foo', diff --git a/tests/Controller/ProjectControllerTest.php b/tests/Controller/ProjectControllerTest.php index ed4a52c4..73bb958c 100644 --- a/tests/Controller/ProjectControllerTest.php +++ b/tests/Controller/ProjectControllerTest.php @@ -49,6 +49,29 @@ class ProjectControllerTest extends ControllerBaseTest $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $this->assertAccessIsGranted($client, '/admin/project/'); $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/project/export'), + 'help' => 'https://www.kimai.org/documentation/project.html' + ]); + } + + public function testIndexActionAsSuperAdmin() + { + $client = $this->getClientForAuthenticatedUser(User::ROLE_SUPER_ADMIN); + $this->assertAccessIsGranted($client, '/admin/project/'); + $this->assertHasDataTable($client); + + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/project/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/project/create'), + 'settings modal-ajax-form' => $this->createUrl('/admin/system-config/edit/project'), + 'help' => 'https://www.kimai.org/documentation/project.html' + ]); } public function testIndexActionWithSearchTermQuery() @@ -67,6 +90,14 @@ class ProjectControllerTest extends ControllerBaseTest $this->assertAccessIsGranted($client, '/admin/project/'); + $this->assertPageActions($client, [ + 'search' => '#', + 'visibility' => '#', + 'download toolbar-action' => $this->createUrl('/admin/project/export'), + 'create modal-ajax-form' => $this->createUrl('/admin/project/create'), + 'help' => 'https://www.kimai.org/documentation/project.html' + ]); + $form = $client->getCrawler()->filter('form.searchform')->form(); $client->submit($form, [ 'searchTerm' => 'feature:timetracking foo', diff --git a/tests/Controller/SystemConfigurationControllerTest.php b/tests/Controller/SystemConfigurationControllerTest.php index 1fec2b8b..7aeaac0a 100644 --- a/tests/Controller/SystemConfigurationControllerTest.php +++ b/tests/Controller/SystemConfigurationControllerTest.php @@ -76,6 +76,8 @@ class SystemConfigurationControllerTest extends ControllerBaseTest ['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')], diff --git a/translations/messages.de.xlf b/translations/messages.de.xlf index fd7ac980..fd97008c 100644 --- a/translations/messages.de.xlf +++ b/translations/messages.de.xlf @@ -116,6 +116,10 @@ modal.dirty Das Formular wurde geändert. Bitte klicken Sie „Speichern“, um die Änderungen zu sichern oder „Schließen“, um abzubrechen. + + Display of entries in selection lists + Darstellung der Einträge in Auswahllisten + diff --git a/translations/messages.en.xlf b/translations/messages.en.xlf index 3e6c9b12..e7d51cca 100644 --- a/translations/messages.en.xlf +++ b/translations/messages.en.xlf @@ -116,6 +116,10 @@ modal.dirty The form has changed. Please click "Save" to save the changes or "Close" to cancel. + + Display of entries in selection lists + Display of entries in selection lists +