prepare release 1.14 (#2495)

* removed un-maintained docker file
* update all packages
* fix deprecations
* only show one line descriptions for customer, projects and activities
* allow to show export column in timesheet listing
This commit is contained in:
Kevin Papst
2021-04-08 18:07:57 +02:00
committed by GitHub
parent 2ce6e815ff
commit af9dea9226
30 changed files with 920 additions and 739 deletions

View File

@@ -15,7 +15,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class NotFoundException extends NotFoundHttpException
{
public function __construct(string $message = 'Not found', \Exception $previous = null, int $code = 0, array $headers = [])
public function __construct(string $message = 'Not found', \Exception $previous = null, int $code = 404, array $headers = [])
{
parent::__construct($message, $previous, $code, $headers);
}

View File

@@ -0,0 +1,45 @@
<?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\EventSubscriber;
use Pagerfanta\Exception\NotValidMaxPerPageException;
use Pagerfanta\Exception\OutOfRangeCurrentPageException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Catches Pagerfanta Exceptions and converts them to "normal" Http Exceptions with status code 404.
* This was mainly done to convert the 500 to 404 HTTP response code.
* This prevents also the need to register them in fos_rest.yaml for the API.
*/
final class PagerfantaExceptionSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
KernelEvents::EXCEPTION => ['onCoreException', 1]
];
}
/**
* @param ExceptionEvent $event
*/
public function onCoreException(ExceptionEvent $event)
{
$throwable = $event->getThrowable();
if ($throwable instanceof NotValidMaxPerPageException || $throwable instanceof OutOfRangeCurrentPageException) {
$notFoundHttpException = new NotFoundHttpException($throwable->getMessage(), $throwable, $throwable->getCode());
$event->setThrowable($notFoundHttpException);
}
}
}

View File

@@ -28,27 +28,25 @@ use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
/**
* Defines the form used to manipulate Timesheet entries.
* @internal
* Helper functions to manage dependent customer-project-activity fields.
*/
trait FormTrait
{
protected function addCustomer(FormBuilderInterface $builder, ?Customer $customer = null)
{
$builder
->add('customer', CustomerType::class, [
'query_builder' => function (CustomerRepository $repo) use ($builder, $customer) {
$query = new CustomerFormTypeQuery($customer);
$query->setUser($builder->getOption('user'));
$builder->add('customer', CustomerType::class, [
'query_builder' => function (CustomerRepository $repo) use ($builder, $customer) {
$query = new CustomerFormTypeQuery($customer);
$query->setUser($builder->getOption('user'));
return $repo->getQueryBuilderForFormType($query);
},
'data' => $customer ? $customer : '',
'required' => false,
'placeholder' => '',
'mapped' => false,
'project_enabled' => true,
]);
return $repo->getQueryBuilderForFormType($query);
},
'data' => $customer ? $customer : '',
'required' => false,
'placeholder' => '',
'mapped' => false,
'project_enabled' => true,
]);
}
protected function addProject(FormBuilderInterface $builder, bool $isNew, ?Project $project = null, ?Customer $customer = null)
@@ -102,17 +100,15 @@ trait FormTrait
protected function addActivity(FormBuilderInterface $builder, ?Activity $activity = null, ?Project $project = null)
{
$builder
->add('activity', ActivityType::class, [
'placeholder' => '',
'query_builder' => function (ActivityRepository $repo) use ($builder, $activity, $project) {
$query = new ActivityFormTypeQuery($activity, $project);
$query->setUser($builder->getOption('user'));
$builder->add('activity', ActivityType::class, [
'placeholder' => '',
'query_builder' => function (ActivityRepository $repo) use ($builder, $activity, $project) {
$query = new ActivityFormTypeQuery($activity, $project);
$query->setUser($builder->getOption('user'));
return $repo->getQueryBuilderForFormType($query);
},
])
;
return $repo->getQueryBuilderForFormType($query);
},
]);
// replaces the activity select after submission, to make sure only activities for the selected project are displayed
$builder->addEventListener(
@@ -143,20 +139,23 @@ trait FormTrait
{
@trigger_error('FormTrait::addDescription() is deprecated and will be removed with 2.0, use DescriptionType instead', E_USER_DEPRECATED);
$builder
->add('description', DescriptionType::class, [
'required' => false,
'attr' => [
'autofocus' => 'autofocus'
]
]);
$builder->add('description', DescriptionType::class, [
'required' => false,
'attr' => [
'autofocus' => 'autofocus'
]
]);
}
/**
* @deprecated since 1.14
*/
protected function addTags(FormBuilderInterface $builder)
{
$builder
->add('tags', TagsType::class, [
'required' => false,
]);
@trigger_error('FormTrait::addTags() is deprecated and will be removed with 2.0, use TagsType instead', E_USER_DEPRECATED);
$builder->add('tags', TagsType::class, [
'required' => false,
]);
}
}

View File

@@ -16,6 +16,7 @@ use App\Form\Type\DurationType;
use App\Form\Type\FixedRateType;
use App\Form\Type\HourlyRateType;
use App\Form\Type\MetaFieldsCollectionType;
use App\Form\Type\TagsType;
use App\Form\Type\UserType;
use App\Form\Type\YesNoType;
use App\Repository\CustomerRepository;
@@ -121,8 +122,7 @@ class TimesheetEditForm extends AbstractType
$descriptionOptions['attr'] = ['autofocus' => 'autofocus'];
}
$builder->add('description', DescriptionType::class, $descriptionOptions);
$this->addTags($builder);
$builder->add('tags', TagsType::class, ['required' => false]);
$this->addRates($builder, $currency, $options);
$this->addUser($builder, $options);
$builder->add('metaFields', MetaFieldsCollectionType::class);

View File

@@ -69,6 +69,36 @@ final class MarkdownExtension implements RuntimeExtensionInterface
return $content;
}
/**
* Transforms the entities comment (customer, project, activity ...) into a one-liner.
*
* @param string|null $content
* @param bool $fullLength
* @return string
*/
public function commentOneLiner(?string $content, bool $fullLength = false): string
{
if (empty($content)) {
return '';
}
$addHellip = false;
if (!$fullLength && \strlen($content) > 52) {
$content = trim(substr($content, 0, 50));
$addHellip = true;
}
$content = explode(PHP_EOL, $content);
$result = $content[0];
if (\count($content) > 1 || $addHellip) {
$result .= ' &hellip;';
}
return $result;
}
/**
* Transforms the timesheet description content into HTML.
*

View File

@@ -44,6 +44,7 @@ class RuntimeExtensions extends AbstractExtension
new TwigFilter('md2html', [MarkdownExtension::class, 'markdownToHtml'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('desc2html', [MarkdownExtension::class, 'timesheetContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment2html', [MarkdownExtension::class, 'commentContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment1line', [MarkdownExtension::class, 'commentOneLiner'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
];
}
}