configure display of customer, project and activity in dropdown lists (#3151)

This commit is contained in:
Kevin Papst
2022-02-14 17:43:05 +01:00
committed by GitHub
parent 83a894823f
commit 7da7468965
17 changed files with 508 additions and 40 deletions

View File

@@ -14,12 +14,15 @@ use App\Event\SystemConfigurationEvent;
use App\Form\Model\Configuration; use App\Form\Model\Configuration;
use App\Form\Model\SystemConfiguration as SystemConfigurationModel; use App\Form\Model\SystemConfiguration as SystemConfigurationModel;
use App\Form\SystemConfigurationForm; use App\Form\SystemConfigurationForm;
use App\Form\Type\ActivityTypePatternType;
use App\Form\Type\ArrayToCommaStringType; use App\Form\Type\ArrayToCommaStringType;
use App\Form\Type\CustomerTypePatternType;
use App\Form\Type\DatePickerType; use App\Form\Type\DatePickerType;
use App\Form\Type\DateTimeTextType; use App\Form\Type\DateTimeTextType;
use App\Form\Type\DayTimeType; use App\Form\Type\DayTimeType;
use App\Form\Type\LanguageType; use App\Form\Type\LanguageType;
use App\Form\Type\MinuteIncrementType; use App\Form\Type\MinuteIncrementType;
use App\Form\Type\ProjectTypePatternType;
use App\Form\Type\RoundingModeType; use App\Form\Type\RoundingModeType;
use App\Form\Type\SkinType; use App\Form\Type\SkinType;
use App\Form\Type\TimezoneType; use App\Form\Type\TimezoneType;
@@ -496,6 +499,24 @@ final class SystemConfigurationController extends AbstractController
->setLabel('currency') ->setLabel('currency')
->setType(CurrencyType::class) ->setType(CurrencyType::class)
->setOptions(['help' => 'default_value_new']), ->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')) (new SystemConfigurationModel('user'))
->setConfiguration([ ->setConfiguration([

View File

@@ -34,6 +34,10 @@ class ActivitiesSubscriber extends AbstractActionsSubscriber
$event->addCreate($this->path('admin_activity_create')); $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')); $event->addHelp($this->documentationLink('activity.html'));
} }
} }

View File

@@ -34,6 +34,10 @@ class CustomersSubscriber extends AbstractActionsSubscriber
$event->addCreate($this->path('admin_customer_create')); $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')); $event->addHelp($this->documentationLink('customer.html'));
} }
} }

View File

@@ -35,6 +35,10 @@ class ProjectsSubscriber extends AbstractActionsSubscriber
$event->addCreate($this->path('admin_project_create')); $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')); $event->addHelp($this->documentationLink('project.html'));
} }
} }

View File

@@ -9,6 +9,7 @@
namespace App\Form\Type; namespace App\Form\Type;
use App\Configuration\SystemConfiguration;
use App\Entity\Activity; use App\Entity\Activity;
use App\Repository\ActivityRepository; use App\Repository\ActivityRepository;
use App\Repository\Query\ActivityFormTypeQuery; use App\Repository\Query\ActivityFormTypeQuery;
@@ -22,6 +23,44 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/ */
class ActivityType extends AbstractType 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} * {@inheritdoc}
*/ */
@@ -35,32 +74,18 @@ class ActivityType extends AbstractType
} }
/** /**
* {@inheritdoc} * @param Activity $activity
*/
public function choiceLabel(Activity $activity)
{
return $activity->getName();
}
/**
* @param Activity $choiceValue
* @param string $key * @param string $key
* @param mixed $value * @param mixed $value
* @return array * @return array
*/ */
public function choiceAttr($choiceValue, $key, $value) public function getChoiceAttributes(Activity $activity, $key, $value)
{ {
$project = null; if (null !== ($project = $activity->getProject())) {
return ['data-project' => $project->getId(), 'data-currency' => $project->getCustomer()->getCurrency()];
if (!($choiceValue instanceof Activity)) {
return [];
} }
if (null !== $choiceValue->getProject()) { return [];
$project = $choiceValue->getProject()->getId();
}
return ['data-project' => $project];
} }
/** /**
@@ -76,9 +101,9 @@ class ActivityType extends AbstractType
], ],
'label' => 'label.activity', 'label' => 'label.activity',
'class' => Activity::class, 'class' => Activity::class,
'choice_label' => [$this, 'choiceLabel'], 'choice_label' => [$this, 'getChoiceLabel'],
'choice_attr' => [$this, 'getChoiceAttributes'],
'group_by' => [$this, 'groupBy'], 'group_by' => [$this, 'groupBy'],
'choice_attr' => [$this, 'choiceAttr'],
'query_builder_for_user' => true, 'query_builder_for_user' => true,
// @var Project|Project[]|int|int[]|null // @var Project|Project[]|int|int[]|null
'projects' => null, 'projects' => null,

View File

@@ -0,0 +1,55 @@
<?php
/*
* 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.
*/
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Select the pattern that will be used when rendering an activity select.
*/
class ActivityTypePatternType extends AbstractType
{
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->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;
}
}

View File

@@ -9,6 +9,7 @@
namespace App\Form\Type; namespace App\Form\Type;
use App\Configuration\SystemConfiguration;
use App\Entity\Customer; use App\Entity\Customer;
use App\Repository\CustomerRepository; use App\Repository\CustomerRepository;
use App\Repository\Query\CustomerFormTypeQuery; use App\Repository\Query\CustomerFormTypeQuery;
@@ -23,6 +24,53 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/ */
class CustomerType extends AbstractType 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} * {@inheritdoc}
*/ */
@@ -36,7 +84,8 @@ class CustomerType extends AbstractType
], ],
'label' => 'label.customer', 'label' => 'label.customer',
'class' => Customer::class, 'class' => Customer::class,
'choice_label' => 'name', 'choice_label' => [$this, 'getChoiceLabel'],
'choice_attr' => [$this, 'getChoiceAttributes'],
'query_builder_for_user' => true, 'query_builder_for_user' => true,
'project_enabled' => false, 'project_enabled' => false,
'project_select' => 'project', 'project_select' => 'project',

View File

@@ -0,0 +1,65 @@
<?php
/*
* 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.
*/
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Select the pattern that will be used when rendering a custom select.
*/
class CustomerTypePatternType extends AbstractType
{
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->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;
}
}

View File

@@ -9,10 +9,12 @@
namespace App\Form\Type; namespace App\Form\Type;
use App\Configuration\SystemConfiguration;
use App\Entity\Project; use App\Entity\Project;
use App\Repository\ProjectRepository; use App\Repository\ProjectRepository;
use App\Repository\Query\ActivityQuery; use App\Repository\Query\ActivityQuery;
use App\Repository\Query\ProjectFormTypeQuery; use App\Repository\Query\ProjectFormTypeQuery;
use App\Utils\LocaleSettings;
use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\Options;
@@ -23,25 +25,93 @@ use Symfony\Component\OptionsResolver\OptionsResolver;
*/ */
class ProjectType extends AbstractType 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 string $key
* @param mixed $value * @param mixed $value
* @return array * @return array
*/ */
public function choiceAttr($choiceValue, $key, $value) public function getChoiceAttributes(Project $project, $key, $value): array
{ {
$customer = null; if (null !== ($customer = $project->getCustomer())) {
return ['data-customer' => $customer->getId(), 'data-currency' => $customer->getCurrency()];
if (!($choiceValue instanceof Project)) {
return [];
} }
if (null !== $choiceValue->getCustomer()) { return [];
$customer = $choiceValue->getCustomer()->getId();
}
return ['data-customer' => $customer];
} }
/** /**
@@ -57,8 +127,8 @@ class ProjectType extends AbstractType
], ],
'label' => 'label.project', 'label' => 'label.project',
'class' => Project::class, 'class' => Project::class,
'choice_label' => 'name', 'choice_label' => [$this, 'getChoiceLabel'],
'choice_attr' => [$this, 'choiceAttr'], 'choice_attr' => [$this, 'getChoiceAttributes'],
'group_by' => function (Project $project, $key, $index) { 'group_by' => function (Project $project, $key, $index) {
return $project->getCustomer()->getName(); return $project->getCustomer()->getName();
}, },

View File

@@ -0,0 +1,61 @@
<?php
/*
* 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.
*/
namespace App\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Contracts\Translation\TranslatorInterface;
/**
* Select the pattern that will be used when rendering a project select.
*/
class ProjectTypePatternType extends AbstractType
{
private $translator;
public function __construct(TranslatorInterface $translator)
{
$this->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;
}
}

View File

@@ -18,13 +18,27 @@ use Symfony\Component\HttpFoundation\RequestStack;
*/ */
final class LocaleSettings extends LocaleFormats final class LocaleSettings extends LocaleFormats
{ {
private $requestStack;
private $locale;
public function __construct(RequestStack $requestStack, LanguageFormattings $formats) public function __construct(RequestStack $requestStack, LanguageFormattings $formats)
{ {
$locale = Constants::DEFAULT_LOCALE; parent::__construct($formats, Constants::DEFAULT_LOCALE);
// request is null in a console command $this->requestStack = $requestStack;
if (null !== $requestStack->getMasterRequest()) { }
$locale = $requestStack->getMasterRequest()->getLocale();
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;
} }
} }

View File

@@ -41,6 +41,30 @@ class ActivityControllerTest extends ControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->assertAccessIsGranted($client, '/admin/activity/'); $this->assertAccessIsGranted($client, '/admin/activity/');
$this->assertHasDataTable($client); $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() public function testIndexActionWithSearchTermQuery()

View File

@@ -43,6 +43,29 @@ class CustomerControllerTest extends ControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->assertAccessIsGranted($client, '/admin/customer/'); $this->assertAccessIsGranted($client, '/admin/customer/');
$this->assertHasDataTable($client); $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() public function testIndexActionWithSearchTermQuery()
@@ -61,6 +84,14 @@ class CustomerControllerTest extends ControllerBaseTest
$this->assertAccessIsGranted($client, '/admin/customer/'); $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(); $form = $client->getCrawler()->filter('form.searchform')->form();
$client->submit($form, [ $client->submit($form, [
'searchTerm' => 'feature:timetracking foo', 'searchTerm' => 'feature:timetracking foo',

View File

@@ -49,6 +49,29 @@ class ProjectControllerTest extends ControllerBaseTest
$client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD); $client = $this->getClientForAuthenticatedUser(User::ROLE_TEAMLEAD);
$this->assertAccessIsGranted($client, '/admin/project/'); $this->assertAccessIsGranted($client, '/admin/project/');
$this->assertHasDataTable($client); $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() public function testIndexActionWithSearchTermQuery()
@@ -67,6 +90,14 @@ class ProjectControllerTest extends ControllerBaseTest
$this->assertAccessIsGranted($client, '/admin/project/'); $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(); $form = $client->getCrawler()->filter('form.searchform')->form();
$client->submit($form, [ $client->submit($form, [
'searchTerm' => 'feature:timetracking foo', 'searchTerm' => 'feature:timetracking foo',

View File

@@ -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_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_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_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_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_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_calendar]', $this->createUrl('/admin/system-config/update/calendar')],

View File

@@ -116,6 +116,10 @@
<source>modal.dirty</source> <source>modal.dirty</source>
<target>Das Formular wurde geändert. Bitte klicken Sie „Speichern“, um die Änderungen zu sichern oder „Schließen“, um abzubrechen.</target> <target>Das Formular wurde geändert. Bitte klicken Sie „Speichern“, um die Änderungen zu sichern oder „Schließen“, um abzubrechen.</target>
</trans-unit> </trans-unit>
<trans-unit id="sdfgsdfgsdfg" resname="label.choice_pattern">
<source>Display of entries in selection lists</source>
<target>Darstellung der Einträge in Auswahllisten</target>
</trans-unit>
<!-- <!--
Login / Security Login / Security
--> -->

View File

@@ -116,6 +116,10 @@
<source>modal.dirty</source> <source>modal.dirty</source>
<target>The form has changed. Please click "Save" to save the changes or "Close" to cancel.</target> <target>The form has changed. Please click "Save" to save the changes or "Close" to cancel.</target>
</trans-unit> </trans-unit>
<trans-unit id="sdfgsdfgsdfg" resname="label.choice_pattern">
<source>Display of entries in selection lists</source>
<target>Display of entries in selection lists</target>
</trans-unit>
<!-- <!--
Login / Security Login / Security
--> -->