export filtered timesheets without additional search form (#5234)

This commit is contained in:
Kevin Papst
2024-12-15 18:38:30 +01:00
committed by GitHub
parent 17a815e5a9
commit 21c031f2c8
33 changed files with 98 additions and 306 deletions

View File

@@ -160,17 +160,13 @@ abstract class AbstractController extends BaseAbstractController implements Serv
*
* @param array<string, string> $parameter
*/
private function addFlashTranslated(string $type, string $message, array $parameter = []): void
private function addFlashTranslated(string $type, string $message, array $parameter = [], string $domain = 'flashmessages'): void
{
if (!empty($parameter)) {
foreach ($parameter as $key => $value) {
$parameter[$key] = $this->getTranslator()->trans($value, [], 'flashmessages');
$parameter[$key] = $this->getTranslator()->trans($value, [], $domain);
}
$message = $this->getTranslator()->trans(
$message,
$parameter,
'flashmessages'
);
$message = $this->getTranslator()->trans($message, $parameter, $domain);
}
$this->addFlash($type, $message);

View File

@@ -23,7 +23,6 @@ use App\Form\MultiUpdate\TimesheetMultiUpdate;
use App\Form\MultiUpdate\TimesheetMultiUpdateDTO;
use App\Form\TimesheetEditForm;
use App\Form\TimesheetPreCreateForm;
use App\Form\Toolbar\TimesheetExportToolbarForm;
use App\Form\Toolbar\TimesheetToolbarForm;
use App\Repository\Query\BaseQuery;
use App\Repository\Query\TimesheetQuery;
@@ -34,7 +33,6 @@ use App\Timesheet\TrackingMode\TrackingModeInterface;
use App\Utils\DataTable;
use App\Utils\PageSetup;
use Psr\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormTypeInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -237,19 +235,22 @@ abstract class TimesheetAbstractController extends AbstractController
]);
}
protected function export(Request $request, ServiceExport $serviceExport): Response
protected function export(string $type, Request $request, ServiceExport $serviceExport): Response
{
$exporter = $serviceExport->getTimesheetExporterById($type);
if (null === $exporter) {
throw $this->createNotFoundException();
}
$query = $this->createDefaultQuery();
$query->setOrder(BaseQuery::ORDER_ASC);
$form = $this->getExportForm($query);
if ($request->isMethod(Request::METHOD_POST)) {
$request->query->set('performSearch', true);
}
$form = $this->getToolbarForm($query);
$request->query->set('performSearch', true);
if ($this->handleSearch($form, $request)) {
return $this->redirectToRoute($this->getExportRoute());
return $this->redirectToRoute($this->getTimesheetRoute());
}
$this->prepareQuery($query);
@@ -263,29 +264,8 @@ abstract class TimesheetAbstractController extends AbstractController
}
$entries = $this->repository->getTimesheetResult($query);
$stats = $entries->getStatistic();
// perform the real export
if ($request->isMethod(Request::METHOD_POST)) {
$type = $request->request->get('exporter');
if (null !== $type) {
$exporter = $serviceExport->getTimesheetExporterById($type);
if (null === $exporter) {
$form->addError(new FormError('Invalid timesheet exporter given'));
} else {
return $exporter->render($entries->getResults(), $query);
}
}
}
return $this->render('timesheet/layout-export.html.twig', [
'page_setup' => new PageSetup('export'),
'form' => $form->createView(),
'route_back' => $this->getTimesheetRoute(),
'exporter' => $serviceExport->getTimesheetExporter(),
'stats' => $stats,
]);
return $exporter->render($entries->getResults(), $query);
}
protected function multiUpdate(Request $request): Response
@@ -548,16 +528,6 @@ abstract class TimesheetAbstractController extends AbstractController
]);
}
private function getExportForm(TimesheetQuery $query): FormInterface
{
return $this->createSearchForm(TimesheetExportToolbarForm::class, $query, [
'action' => $this->generateUrl($this->getExportRoute()),
'timezone' => $this->getDateTimeFactory()->getTimezone()->getName(),
'method' => Request::METHOD_POST,
'include_user' => $this->includeUserInForms('toolbar'),
]);
}
protected function getPermissionEditExport(): string
{
return 'edit_export_own_timesheet';
@@ -611,11 +581,6 @@ abstract class TimesheetAbstractController extends AbstractController
return 'timesheet_multi_delete';
}
protected function getExportRoute(): string
{
return 'timesheet_export';
}
protected function canSeeStartEndTime(): bool
{
return $this->getTrackingMode()->canSeeBeginAndEndTimes();

View File

@@ -41,11 +41,11 @@ final class TimesheetController extends TimesheetAbstractController
return $this->index($query, $request, 'timesheet', 'timesheet_paginated', TimesheetMetaDisplayEvent::TIMESHEET);
}
#[Route(path: '/export/', name: 'timesheet_export', methods: ['GET', 'POST'])]
#[Route(path: '/export/{exporter}', name: 'timesheet_export', methods: ['GET', 'POST'])]
#[IsGranted('export_own_timesheet')]
public function exportAction(Request $request, ServiceExport $serviceExport): Response
public function exportAction(string $exporter, Request $request, ServiceExport $serviceExport): Response
{
return $this->export($request, $serviceExport);
return $this->export($exporter, $request, $serviceExport);
}
#[Route(path: '/{id}/edit', name: 'timesheet_edit', methods: ['GET', 'POST'])]

View File

@@ -50,11 +50,11 @@ final class TimesheetTeamController extends TimesheetAbstractController
return $this->index($query, $request, 'admin_timesheet', 'admin_timesheet_paginated', TimesheetMetaDisplayEvent::TEAM_TIMESHEET);
}
#[Route(path: '/export/', name: 'admin_timesheet_export', methods: ['GET', 'POST'])]
#[Route(path: '/export/{exporter}', name: 'admin_timesheet_export', methods: ['GET', 'POST'])]
#[IsGranted('export_other_timesheet')]
public function exportAction(Request $request, ServiceExport $serviceExport): Response
public function exportAction(string $exporter, Request $request, ServiceExport $serviceExport): Response
{
return $this->export($request, $serviceExport);
return $this->export($exporter, $request, $serviceExport);
}
#[Route(path: '/{id}/edit', name: 'admin_timesheet_edit', methods: ['GET', 'POST'])]
@@ -233,11 +233,6 @@ final class TimesheetTeamController extends TimesheetAbstractController
return 'admin_timesheet_edit';
}
protected function getExportRoute(): string
{
return 'admin_timesheet_export';
}
protected function getMultiUpdateRoute(): string
{
return 'admin_timesheet_multi_update';

View File

@@ -10,9 +10,17 @@
namespace App\EventSubscriber\Actions;
use App\Event\PageActionsEvent;
use App\Export\ServiceExport;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
final class TimesheetsSubscriber extends AbstractActionsSubscriber
{
public function __construct(AuthorizationCheckerInterface $auth, UrlGeneratorInterface $urlGenerator, private readonly ServiceExport $serviceExport)
{
parent::__construct($auth, $urlGenerator);
}
public static function getActionName(): string
{
return 'timesheets';
@@ -25,7 +33,9 @@ final class TimesheetsSubscriber extends AbstractActionsSubscriber
}
if ($this->isGranted('export_own_timesheet')) {
$event->addAction('download', ['url' => $this->path('timesheet_export'), 'class' => 'modal-ajax-form', 'title' => 'export']);
foreach ($this->serviceExport->getTimesheetExporter() as $exporter) {
$event->addActionToSubmenu('export', $exporter->getId(), ['url' => $this->path('timesheet_export', ['exporter' => $exporter->getId()]), 'class' => 'toolbar-action', 'title' => 'button.' . $exporter->getId(), 'translation_domain' => 'messages']);
}
}
}
}

View File

@@ -10,9 +10,17 @@
namespace App\EventSubscriber\Actions;
use App\Event\PageActionsEvent;
use App\Export\ServiceExport;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
final class TimesheetsTeamSubscriber extends AbstractActionsSubscriber
{
public function __construct(AuthorizationCheckerInterface $auth, UrlGeneratorInterface $urlGenerator, private readonly ServiceExport $serviceExport)
{
parent::__construct($auth, $urlGenerator);
}
public static function getActionName(): string
{
return 'timesheets_team';
@@ -26,7 +34,9 @@ final class TimesheetsTeamSubscriber extends AbstractActionsSubscriber
}
if ($this->isGranted('export_other_timesheet')) {
$event->addAction('download', ['url' => $this->path('admin_timesheet_export'), 'class' => 'modal-ajax-form', 'title' => 'export']);
foreach ($this->serviceExport->getTimesheetExporter() as $exporter) {
$event->addActionToSubmenu('export', $exporter->getId(), ['url' => $this->path('admin_timesheet_export', ['exporter' => $exporter->getId()]), 'class' => 'toolbar-action', 'title' => 'button.' . $exporter->getId(), 'translation_domain' => 'messages']);
}
}
}
}

View File

@@ -27,11 +27,6 @@ interface ExportRendererInterface
*/
public function getId(): string;
/**
* @return string
*/
public function getIcon(): string;
/**
* @return string
*/

View File

@@ -14,11 +14,6 @@ use App\Export\RendererInterface;
final class CsvRenderer extends BaseCsvRenderer implements RendererInterface
{
public function getIcon(): string
{
return 'csv';
}
public function getTitle(): string
{
return 'csv';

View File

@@ -14,11 +14,6 @@ use App\Export\ExportRendererInterface;
final class HtmlRenderer extends BaseHtmlRenderer implements ExportRendererInterface
{
public function getIcon(): string
{
return 'print';
}
public function getTitle(): string
{
return 'print';

View File

@@ -14,11 +14,6 @@ use App\Export\ExportRendererInterface;
final class PDFRenderer extends BasePDFRenderer implements ExportRendererInterface
{
public function getIcon(): string
{
return 'pdf';
}
public function getTitle(): string
{
return 'pdf';

View File

@@ -14,11 +14,6 @@ use App\Export\RendererInterface;
final class XlsxRenderer extends BaseXlsxRenderer implements RendererInterface
{
public function getIcon(): string
{
return 'xlsx';
}
public function getTitle(): string
{
return 'xlsx';

View File

@@ -14,4 +14,8 @@ use App\Export\TimesheetExportInterface;
final class CsvRenderer extends BaseCsvRenderer implements TimesheetExportInterface
{
public function getTitle(): string
{
return 'csv';
}
}

View File

@@ -19,11 +19,13 @@ final class HtmlRenderer extends BaseHtmlRenderer implements TimesheetExportInte
return 'timesheet/export.html.twig';
}
/**
* @return string
*/
public function getId(): string
{
return 'print';
}
public function getTitle(): string
{
return 'print';
}
}

View File

@@ -14,4 +14,8 @@ use App\Export\TimesheetExportInterface;
final class PDFRenderer extends BasePDFRenderer implements TimesheetExportInterface
{
public function getTitle(): string
{
return 'pdf';
}
}

View File

@@ -14,4 +14,8 @@ use App\Export\TimesheetExportInterface;
final class XlsxRenderer extends BaseXlsxRenderer implements TimesheetExportInterface
{
public function getTitle(): string
{
return 'xlsx';
}
}

View File

@@ -19,13 +19,10 @@ interface TimesheetExportInterface
{
/**
* @param Timesheet[] $timesheets
* @param TimesheetQuery $query
* @return Response
*/
public function render(array $timesheets, TimesheetQuery $query): Response;
/**
* @return string
*/
public function getId(): string;
public function getTitle(): string;
}

View File

@@ -12,7 +12,6 @@ namespace App\Form\Extension;
use App\Form\Helper\ToolbarHelper;
use App\Form\Toolbar\ExportToolbarForm;
use App\Form\Toolbar\InvoiceToolbarForm;
use App\Form\Toolbar\TimesheetExportToolbarForm;
use App\Form\Toolbar\TimesheetToolbarForm;
use App\Form\Toolbar\UserToolbarForm;
use App\Reporting\MonthlyUserList\MonthlyUserListForm;
@@ -33,7 +32,6 @@ final class ToolbarFormExtension extends AbstractTypeExtension
InvoiceToolbarForm::class,
ExportToolbarForm::class,
TimesheetToolbarForm::class,
TimesheetExportToolbarForm::class,
UserToolbarForm::class,
WeeklyUserListForm::class,
MonthlyUserListForm::class,

View File

@@ -1,58 +0,0 @@
<?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\Toolbar;
use App\Repository\Query\TimesheetQuery;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Defines the form used for filtering the timesheet.
* @extends AbstractType<TimesheetQuery>
*/
final class TimesheetExportToolbarForm extends AbstractType
{
use ToolbarFormTrait;
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$newOptions = [];
if ($options['ignore_date'] === true) {
$newOptions['ignore_date'] = true;
}
$this->addSearchTermInputField($builder);
$this->addDateRange($builder, ['timezone' => $options['timezone']]);
$this->addCustomerMultiChoice($builder, $newOptions, true);
$this->addProjectMultiChoice($builder, $newOptions, true, true);
$this->addActivityMultiChoice($builder, [], true);
$this->addTagInputField($builder);
if ($options['include_user']) {
$this->addUsersChoice($builder);
}
$this->addTimesheetStateChoice($builder);
$this->addBillableChoice($builder);
$this->addExportStateChoice($builder);
$this->addOrder($builder);
$this->addOrderBy($builder, TimesheetQuery::TIMESHEET_ORDER_ALLOWED);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => TimesheetQuery::class,
'csrf_protection' => false,
'include_user' => false,
'ignore_date' => true,
'timezone' => date_default_timezone_get(),
]);
}
}