Release 2.31 (#5372)

* simplify translation
* bump version
* deprecate translations
* pass date-range as argument to export and timesheet filter URL from monthly overview report
* added class for use in responsive screens
* show technical role name
* simplify multi-update title
* more statistic models
* bump composer packages
This commit is contained in:
Kevin Papst
2025-02-27 17:41:25 +01:00
committed by GitHub
parent 674bf3a6b5
commit 14cdcd3f63
20 changed files with 364 additions and 251 deletions

View File

@@ -17,11 +17,11 @@ final class Constants
/**
* The current release version
*/
public const VERSION = '2.30.0';
public const VERSION = '2.31.0';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 23000;
public const VERSION_ID = 23100;
/**
* The software name
*/

View File

@@ -38,7 +38,11 @@ final class DashboardController extends AbstractController
*/
private ?array $widgets = null;
public function __construct(private EventDispatcherInterface $eventDispatcher, private WidgetService $service, private BookmarkRepository $repository)
public function __construct(
private readonly EventDispatcherInterface $eventDispatcher,
private readonly WidgetService $service,
private readonly BookmarkRepository $repository
)
{
}

View File

@@ -59,11 +59,12 @@ final class ProjectDateRangeController extends AbstractController
$byCustomer[$customer->getId()]['projects'][] = $entry;
}
return $this->render('reporting/project_daterange.html.twig', [
return $this->render('reporting/project/daterange.html.twig', [
'report_title' => 'report_project_daterange',
'entries' => $byCustomer,
'form' => $form->createView(),
'queryEnd' => $dateRange->getEnd(),
'queryBegin' => $begin,
'queryEnd' => $end,
]);
}
}

View File

@@ -50,16 +50,21 @@ final class ProjectSubscriber extends AbstractActionsSubscriber
$event->addDivider();
}
$dateRange = '';
if (isset($payload['daterange']) && \is_string($payload['daterange'])) {
$dateRange = $payload['daterange'];
}
if ($this->isGranted('view_activity')) {
$event->addActionToSubmenu('filter', 'activity', ['title' => 'activities', 'url' => $this->path('admin_activity', ['customers[]' => $customer->getId(), 'projects[]' => $project->getId()])]);
}
if ($this->isGranted('view_other_timesheet')) {
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet.filter', 'url' => $this->path('admin_timesheet', ['customers[]' => $customer->getId(), 'projects[]' => $project->getId()])]);
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet.filter', 'url' => $this->path('admin_timesheet', ['customers[]' => $customer->getId(), 'projects[]' => $project->getId(), 'daterange' => $dateRange])]);
}
if ($this->isGranted('create_export')) {
$event->addActionToSubmenu('filter', 'export', ['title' => 'export', 'url' => $this->path('export', ['customers[]' => $customer->getId(), 'projects[]' => $project->getId(), 'exported' => 1, 'daterange' => ''])]);
$event->addActionToSubmenu('filter', 'export', ['title' => 'export', 'url' => $this->path('export', ['customers[]' => $customer->getId(), 'projects[]' => $project->getId(), 'exported' => 1, 'daterange' => $dateRange])]);
}
if ($event->hasSubmenu('filter')) {

View File

@@ -0,0 +1,54 @@
<?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\Model\Statistic;
final class DateRange
{
/**
* @var array<string, StatisticDate>
*/
private array $days = [];
public function __construct(\DateTimeInterface $begin, \DateTimeInterface $end)
{
if ($end < $begin) {
throw new \InvalidArgumentException('End must be later than begin');
}
$begin = \DateTimeImmutable::createFromInterface($begin);
$begin = $begin->setTime(0, 0, 0);
$end = \DateTimeImmutable::createFromInterface($end);
$end = $end->setTime(23, 59, 59);
do {
$this->days[$begin->format('Y-m-d')] = new StatisticDate($begin);
$begin = $begin->modify('+1 day');
} while ($begin <= $end);
}
/**
* @return array<StatisticDate>
*/
public function getDays(): array
{
return array_values($this->days);
}
public function setDate(StatisticDate $date): void
{
$key = $date->getDate()->format('Y-m-d');
if (!\array_key_exists($key, $this->days)) {
throw new \InvalidArgumentException('Unknown date given');
}
$this->days[$key] = $date;
}
}

View File

@@ -14,6 +14,7 @@ final class StatisticDate extends Timesheet
private \DateTimeInterface $date;
private int $billableDuration = 0;
private float $billableRate = 0.00;
private int $amount = 0;
public function __construct(\DateTimeInterface $date)
{
@@ -44,4 +45,14 @@ final class StatisticDate extends Timesheet
{
$this->billableRate = $billableRate;
}
public function getAmount(): int
{
return $this->amount;
}
public function setAmount(int $amount): void
{
$this->amount = $amount;
}
}

View File

@@ -11,6 +11,7 @@ namespace App\Twig;
use App\Constants;
use App\Entity\EntityWithMetaFields;
use App\Form\Type\DateRangeType;
use App\Utils\Color;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;
@@ -37,6 +38,7 @@ final class Extensions extends AbstractExtension
public function getFunctions(): array
{
return [
new TwigFunction('date_range', [$this, 'buildDateRange']),
new TwigFunction('report_date', [$this, 'buildReportDate']),
new TwigFunction('class_name', [$this, 'getClassName']),
new TwigFunction('iso_day_by_name', [$this, 'getIsoDayByName']),
@@ -90,6 +92,11 @@ final class Extensions extends AbstractExtension
return $dateTime->format(self::REPORT_DATE);
}
public function buildDateRange(\DateTimeInterface $begin, \DateTimeInterface $end): string
{
return $begin->format(self::REPORT_DATE) . DateRangeType::DATE_SPACER . $end->format(self::REPORT_DATE);
}
public function getIsoDayByName(string $weekDay): int
{
$key = array_search(