refactored page actions to event subscriber (#2420)
This commit is contained in:
@@ -232,6 +232,10 @@ final class ActivityController extends AbstractController
|
||||
$this->repository->saveActivity($activity);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
if ($this->isGranted('view', $activity)) {
|
||||
return $this->redirectToRoute('activity_details', ['id' => $activity->getId()]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_activity');
|
||||
} catch (Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
|
||||
@@ -142,6 +142,10 @@ final class CustomerController extends AbstractController
|
||||
$this->repository->saveCustomer($customer);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
if ($this->isGranted('view', $customer)) {
|
||||
return $this->redirectToRoute('customer_details', ['id' => $customer->getId()]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_customer');
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
|
||||
@@ -136,6 +136,10 @@ final class ProjectController extends AbstractController
|
||||
$this->projectService->updateProject($project);
|
||||
$this->flashSuccess('action.update.success');
|
||||
|
||||
if ($this->isGranted('view', $project)) {
|
||||
return $this->redirectToRoute('project_details', ['id' => $project->getId()]);
|
||||
}
|
||||
|
||||
return $this->redirectToRoute('admin_project');
|
||||
} catch (\Exception $ex) {
|
||||
$this->flashUpdateException($ex);
|
||||
|
||||
@@ -49,6 +49,9 @@ class ActivityMeta implements MetaTableTypeInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Activity|null
|
||||
*/
|
||||
public function getEntity(): ?EntityWithMetaFields
|
||||
{
|
||||
return $this->activity;
|
||||
|
||||
@@ -49,6 +49,9 @@ class CustomerMeta implements MetaTableTypeInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Customer|null
|
||||
*/
|
||||
public function getEntity(): ?EntityWithMetaFields
|
||||
{
|
||||
return $this->customer;
|
||||
|
||||
@@ -49,6 +49,9 @@ class ProjectMeta implements MetaTableTypeInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Project|null
|
||||
*/
|
||||
public function getEntity(): ?EntityWithMetaFields
|
||||
{
|
||||
return $this->project;
|
||||
|
||||
@@ -367,6 +367,11 @@ class Timesheet implements EntityWithMetaFields, ExportItemInterface
|
||||
return $this->end;
|
||||
}
|
||||
|
||||
public function isRunning(): bool
|
||||
{
|
||||
return $this->end === null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime $end
|
||||
* @return Timesheet
|
||||
|
||||
@@ -49,6 +49,9 @@ class TimesheetMeta implements MetaTableTypeInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Timesheet|null
|
||||
*/
|
||||
public function getEntity(): ?EntityWithMetaFields
|
||||
{
|
||||
return $this->timesheet;
|
||||
|
||||
@@ -11,17 +11,29 @@ namespace App\Event;
|
||||
|
||||
use App\Entity\User;
|
||||
|
||||
/**
|
||||
* This event is triggered once per side load.
|
||||
* It stores all toolbar items, which should be rendered in the upper right corner.
|
||||
*/
|
||||
class PageActionsEvent extends ThemeEvent
|
||||
{
|
||||
private $action;
|
||||
private $view;
|
||||
private $divider = 0;
|
||||
|
||||
public function __construct(User $user, array $payload, string $action)
|
||||
public function __construct(User $user, array $payload, string $action, string $view)
|
||||
{
|
||||
// only for BC reasons, do not access it directly!
|
||||
if (!\array_key_exists('actions', $payload)) {
|
||||
$payload['actions'] = [];
|
||||
}
|
||||
// only for BC reasons, do not access it directly!
|
||||
if (!\array_key_exists('view', $payload)) {
|
||||
$payload['view'] = $view;
|
||||
}
|
||||
parent::__construct($user, $payload);
|
||||
$this->action = $action;
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
public function getActionName(): string
|
||||
@@ -29,13 +41,141 @@ class PageActionsEvent extends ThemeEvent
|
||||
return $this->action;
|
||||
}
|
||||
|
||||
public function getActions(): array
|
||||
public function isView(string $view): bool
|
||||
{
|
||||
return $this->payload['actions'];
|
||||
return $this->view === $view;
|
||||
}
|
||||
|
||||
public function setActions(array $actions): void
|
||||
public function isIndexView(): bool
|
||||
{
|
||||
$this->payload['actions'] = $actions;
|
||||
return $this->isView('index');
|
||||
}
|
||||
|
||||
public function getView(): string
|
||||
{
|
||||
return $this->view;
|
||||
}
|
||||
|
||||
public function getActions(): array
|
||||
{
|
||||
$actions = $this->payload['actions'];
|
||||
|
||||
// move documentation to end of list
|
||||
if (\array_key_exists('help', $actions)) {
|
||||
$help = $actions['help'];
|
||||
unset($actions['help']);
|
||||
$actions += ['help' => $help];
|
||||
}
|
||||
|
||||
// move trash to end of list
|
||||
if (\array_key_exists('trash', $actions)) {
|
||||
$delete = $actions['trash'];
|
||||
unset($actions['trash']);
|
||||
$actions += ['trash' => $delete];
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
public function hasAction(string $key): bool
|
||||
{
|
||||
return \array_key_exists($key, $this->payload['actions']);
|
||||
}
|
||||
|
||||
public function hasSubmenu(string $submenu): bool
|
||||
{
|
||||
if (!\array_key_exists($submenu, $this->payload['actions'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return \array_key_exists('children', $this->payload['actions'][$submenu]);
|
||||
}
|
||||
|
||||
public function addActionToSubmenu(string $submenu, string $key, array $action): void
|
||||
{
|
||||
if (\array_key_exists($submenu, $this->payload['actions'])) {
|
||||
if (!\array_key_exists('children', $this->payload['actions'][$submenu])) {
|
||||
$this->payload['actions'][$submenu]['children'] = [];
|
||||
}
|
||||
}
|
||||
$this->payload['actions'][$submenu]['children'][$key] = $action;
|
||||
}
|
||||
|
||||
public function replaceAction(string $key, array $action): void
|
||||
{
|
||||
$this->payload['actions'][$key] = $action;
|
||||
}
|
||||
|
||||
public function addAction(string $key, array $action): void
|
||||
{
|
||||
if (!\array_key_exists($key, $this->payload['actions'])) {
|
||||
$this->payload['actions'][$key] = $action;
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAction(string $key): void
|
||||
{
|
||||
if (\array_key_exists($key, $this->payload['actions'])) {
|
||||
unset($this->payload['actions'][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
public function addDivider(): void
|
||||
{
|
||||
$key = 'divider' . $this->divider++;
|
||||
$this->payload['actions'][$key] = null;
|
||||
}
|
||||
|
||||
public function addSearchToggle(): void
|
||||
{
|
||||
$this->addAction('search', ['class' => 'search-toggle visible-xs-inline']);
|
||||
}
|
||||
|
||||
public function addQuickExport(string $url): void
|
||||
{
|
||||
$this->addAction('download', ['url' => $url, 'class' => 'toolbar-action']);
|
||||
}
|
||||
|
||||
public function addCreate(string $url, bool $modal = true): void
|
||||
{
|
||||
$this->addAction('create', ['url' => $url, 'class' => ($modal ? 'modal-ajax-form' : '')]);
|
||||
}
|
||||
|
||||
public function addHelp(string $url): void
|
||||
{
|
||||
$this->addAction('help', ['url' => $url, 'target' => '_blank']);
|
||||
}
|
||||
|
||||
public function addBack(string $url): void
|
||||
{
|
||||
$this->addAction('back', ['url' => $url, 'translation_domain' => 'actions']);
|
||||
}
|
||||
|
||||
public function addDelete(string $url, bool $remoteConfirm = true): void
|
||||
{
|
||||
if ($remoteConfirm) {
|
||||
$this->addAction('trash', ['url' => $url, 'class' => 'modal-ajax-form text-red']);
|
||||
} else {
|
||||
$this->addAction('trash', ['url' => $url, 'class' => 'confirmation-link text-red', 'attr' => ['data-question' => 'confirm.delete']]);
|
||||
}
|
||||
}
|
||||
|
||||
public function addColumnToggle(string $modal): void
|
||||
{
|
||||
$modal = '#' . ltrim($modal, '#');
|
||||
$this->addAction('visibility', ['modal' => $modal]);
|
||||
}
|
||||
|
||||
public function countActions(?string $submenu = null): int
|
||||
{
|
||||
if ($submenu !== null) {
|
||||
if (!$this->hasSubmenu($submenu)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return \count($this->payload['actions'][$submenu]['children']);
|
||||
}
|
||||
|
||||
return \count($this->payload['actions']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,10 +10,14 @@
|
||||
namespace App\EventSubscriber\Actions;
|
||||
|
||||
use App\Constants;
|
||||
use App\Event\PageActionsEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
/**
|
||||
* Base class for all listeners, which adds the pages default toolbars.
|
||||
*/
|
||||
abstract class AbstractActionsSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
private $auth;
|
||||
@@ -39,4 +43,21 @@ abstract class AbstractActionsSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
return Constants::HOMEPAGE . '/documentation/' . $url;
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents(): array
|
||||
{
|
||||
return [
|
||||
'actions.' . static::getActionName() => ['onActions', 1000],
|
||||
];
|
||||
}
|
||||
|
||||
public static function getActionName(): string
|
||||
{
|
||||
throw new \Exception('You need to overwrite getActionName() or getSubscribedEvents() in ' . static::class);
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
// non abstract - so the usage is completely optional
|
||||
}
|
||||
}
|
||||
|
||||
58
src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php
Normal file
58
src/EventSubscriber/Actions/AbstractTimesheetSubscriber.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Timesheet;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
abstract class AbstractTimesheetSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
protected function timesheetActions(PageActionsEvent $event, string $routeListing, string $routeEdit): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Timesheet $timesheet */
|
||||
$timesheet = $payload['timesheet'];
|
||||
if (!$event->isIndexView()) {
|
||||
$event->addBack($this->path($routeListing));
|
||||
}
|
||||
|
||||
if ($timesheet->getId() !== null) {
|
||||
if ($this->isGranted('edit', $timesheet)) {
|
||||
$class = $event->isView('edit') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('edit', ['url' => $this->path($routeEdit, ['id' => $timesheet->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($timesheet->isRunning() && $this->isGranted('stop', $timesheet)) {
|
||||
$event->addAction('stop', ['url' => $this->path('stop_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link', 'attr' => ['data-event' => 'kimai.timesheetStop kimai.timesheetUpdate', 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.stop.error', 'data-msg-success' => 'timesheet.stop.success']]);
|
||||
}
|
||||
|
||||
if (!$timesheet->isRunning() && $this->isGranted('start', $timesheet)) {
|
||||
$event->addAction('repeat', ['url' => $this->path('restart_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link', 'attr' => ['data-payload' => '{"copy": "all"}', 'data-event' => 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method' => 'PATCH', 'data-msg-error' => 'timesheet.start.error', 'data-msg-success' => 'timesheet.start.success']]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('duplicate', $timesheet)) {
|
||||
$event->addAction('copy', ['url' => $this->path('duplicate_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link', 'attr' => ['data-payload' => '{"copy": "all"}', 'data-event' => 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method' => 'PATCH', 'data-msg-error' => 'action.update.error', 'data-msg-success' => 'action.update.success']]);
|
||||
}
|
||||
|
||||
if ($event->countActions() > 0) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $timesheet)) {
|
||||
$event->addAction('trash', ['url' => $this->path('delete_timesheet', ['id' => $timesheet->getId()]), 'class' => 'api-link', 'attr' => ['data-event' => 'kimai.timesheetDelete kimai.timesheetUpdate', 'data-method' => 'DELETE', 'data-question' => 'confirm.delete', 'data-msg-error' => 'action.delete.error', 'data-msg-success' => 'action.delete.success']]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!$event->isIndexView()) {
|
||||
$event->addHelp($this->documentationLink('timesheet.html'));
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/EventSubscriber/Actions/AbstractTimesheetsSubscriber.php
Normal file
39
src/EventSubscriber/Actions/AbstractTimesheetsSubscriber.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
use App\Export\ServiceExport;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
abstract class AbstractTimesheetsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
private $serviceExport;
|
||||
|
||||
public function __construct(AuthorizationCheckerInterface $security, UrlGeneratorInterface $urlGenerator, ServiceExport $serviceExport)
|
||||
{
|
||||
parent::__construct($security, $urlGenerator);
|
||||
$this->serviceExport = $serviceExport;
|
||||
}
|
||||
|
||||
protected function addExporter(PageActionsEvent $event, string $routeExport): void
|
||||
{
|
||||
$allExporter = $this->serviceExport->getTimesheetExporter();
|
||||
if (\count($allExporter) === 1) {
|
||||
$event->addAction('download', ['url' => $this->path($routeExport, ['exporter' => $allExporter[0]->getId()]), 'class' => 'toolbar-action']);
|
||||
} else {
|
||||
foreach ($allExporter as $exporter) {
|
||||
$id = $exporter->getId();
|
||||
$event->addActionToSubmenu('download', 'exporter.' . $id, ['title' => 'button.' . $id, 'url' => $this->path($routeExport, ['exporter' => $id]), 'class' => 'toolbar-action exporter-' . $id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/EventSubscriber/Actions/ActivitiesSubscriber.php
Normal file
33
src/EventSubscriber/Actions/ActivitiesSubscriber.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class ActivitiesSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'activities';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_activity_admin');
|
||||
$event->addQuickExport($this->path('activity_export'));
|
||||
|
||||
if ($this->isGranted('create_activity')) {
|
||||
$event->addCreate($this->path('admin_activity_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('activity.html'));
|
||||
}
|
||||
}
|
||||
75
src/EventSubscriber/Actions/ActivitySubscriber.php
Normal file
75
src/EventSubscriber/Actions/ActivitySubscriber.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Activity;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class ActivitySubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'activity';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Activity $activity */
|
||||
$activity = $payload['activity'];
|
||||
|
||||
if ($activity->getId() === null) {
|
||||
return;
|
||||
}
|
||||
if ($this->isGranted('view', $activity)) {
|
||||
$event->addAction('details', ['url' => $this->path('activity_details', ['id' => $activity->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('edit', $activity)) {
|
||||
$class = $event->isView('edit') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('edit', ['url' => $this->path('admin_activity_edit', ['id' => $activity->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('permissions', $activity)) {
|
||||
$class = $event->isView('permissions') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('permissions', ['url' => $this->path('admin_activity_permissions', ['id' => $activity->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($event->countActions() > 0) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_other_timesheet')) {
|
||||
$parameters = ['activities[]' => $activity->getId()];
|
||||
if (!$activity->isGlobal()) {
|
||||
$parameters['customers[]'] = $activity->getProject()->getCustomer()->getId();
|
||||
$parameters['projects[]'] = $activity->getProject()->getId();
|
||||
}
|
||||
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet', 'translation_domain' => 'actions', 'url' => $this->path('admin_timesheet', $parameters)]);
|
||||
}
|
||||
|
||||
if ($event->hasSubmenu('filter')) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($activity->isVisible() && $this->isGranted('create_other_timesheet')) {
|
||||
$parameters = ['activity' => $activity->getId()];
|
||||
if (!$activity->isGlobal()) {
|
||||
$parameters['project'] = $activity->getProject()->getId();
|
||||
}
|
||||
$event->addAction('create-timesheet', ['icon' => 'start', 'url' => $this->path('admin_timesheet_create', $parameters), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $activity)) {
|
||||
$event->addDelete($this->path('admin_activity_delete', ['id' => $activity->getId()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
29
src/EventSubscriber/Actions/CalendarSubscriber.php
Normal file
29
src/EventSubscriber/Actions/CalendarSubscriber.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class CalendarSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'calendar';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
if ($this->isGranted('create_own_timesheet')) {
|
||||
$event->addCreate($this->path('timesheet_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('calendar.html'));
|
||||
}
|
||||
}
|
||||
79
src/EventSubscriber/Actions/CustomerSubscriber.php
Normal file
79
src/EventSubscriber/Actions/CustomerSubscriber.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Customer;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class CustomerSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'customer';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Customer $customer */
|
||||
$customer = $payload['customer'];
|
||||
|
||||
if ($customer->getId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('view', $customer)) {
|
||||
$event->addAction('details', ['url' => $this->path('customer_details', ['id' => $customer->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('edit', $customer)) {
|
||||
$class = $event->isView('edit') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('edit', ['url' => $this->path('admin_customer_edit', ['id' => $customer->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('permissions', $customer)) {
|
||||
$class = $event->isView('permissions') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('permissions', ['url' => $this->path('admin_customer_permissions', ['id' => $customer->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($event->countActions() > 0) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_project') || $this->isGranted('view_teamlead_project') || $this->isGranted('view_team_project')) {
|
||||
$event->addActionToSubmenu('filter', 'project', ['title' => 'project', 'translation_domain' => 'actions', 'url' => $this->path('admin_project', ['customers[]' => $customer->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_activity')) {
|
||||
$event->addActionToSubmenu('filter', 'activity', ['title' => 'activity', 'translation_domain' => 'actions', 'url' => $this->path('admin_activity', ['customers[]' => $customer->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_other_timesheet')) {
|
||||
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet', 'translation_domain' => 'actions', 'url' => $this->path('admin_timesheet', ['customers[]' => $customer->getId()])]);
|
||||
}
|
||||
|
||||
if ($event->hasSubmenu('filter')) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($customer->isVisible() && $this->isGranted('create_project')) {
|
||||
$event->addAction('create-project', ['icon' => 'create', 'url' => $this->path('admin_project_create_with_customer', ['customer' => $customer->getId()]), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $customer)) {
|
||||
$event->addAction('trash', ['url' => $this->path('admin_customer_delete', ['id' => $customer->getId()]), 'class' => 'modal-ajax-form text-red']);
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_reporting') && $this->isGranted('budget_project')) {
|
||||
$event->addAction('report_project_view', ['url' => $this->path('report_project_view', ['customer' => $customer->getId()]), 'icon' => 'reporting', 'translation_domain' => 'reporting']);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/EventSubscriber/Actions/CustomersSubscriber.php
Normal file
33
src/EventSubscriber/Actions/CustomersSubscriber.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class CustomersSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'customers';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_customer_admin');
|
||||
$event->addQuickExport($this->path('customer_export'));
|
||||
|
||||
if ($this->isGranted('create_customer')) {
|
||||
$event->addCreate($this->path('admin_customer_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('customer.html'));
|
||||
}
|
||||
}
|
||||
31
src/EventSubscriber/Actions/ExportSubscriber.php
Normal file
31
src/EventSubscriber/Actions/ExportSubscriber.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class ExportSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'export';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addColumnToggle('#modal_export');
|
||||
|
||||
if ($event->isView('preview')) {
|
||||
$event->addAction('off', ['id' => 'export-toggle-button']);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('export.html'));
|
||||
}
|
||||
}
|
||||
@@ -13,25 +13,19 @@ use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoiceArchiveSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return [
|
||||
'actions.invoice_details' => ['onActions', 1000],
|
||||
];
|
||||
return 'invoice_details';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event)
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$actions = $event->getActions();
|
||||
|
||||
if ($this->isGranted('view_invoice')) {
|
||||
$actions['back'] = ['url' => $this->path('invoice'), 'translation_domain' => 'actions'];
|
||||
$event->addBack($this->path('invoice'));
|
||||
}
|
||||
|
||||
$actions['visibility'] = '#modal_invoices';
|
||||
$actions['download'] = ['url' => $this->path('invoice_export'), 'class' => 'toolbar-action'];
|
||||
$actions['help'] = ['url' => $this->documentationLink('invoices.html'), 'target' => '_blank'];
|
||||
|
||||
$event->setActions($actions);
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_invoices');
|
||||
$event->addQuickExport($this->path('invoice_export'));
|
||||
$event->addHelp($this->documentationLink('invoices.html'));
|
||||
}
|
||||
}
|
||||
|
||||
44
src/EventSubscriber/Actions/InvoiceSubscriber.php
Normal file
44
src/EventSubscriber/Actions/InvoiceSubscriber.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Invoice;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoiceSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'invoice';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Invoice $invoice */
|
||||
$invoice = $payload['invoice'];
|
||||
|
||||
if ($invoice->getId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('history_invoice')) {
|
||||
if ($invoice->isNew()) {
|
||||
$event->addAction('invoice.pending', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'pending'])]);
|
||||
} elseif ($invoice->isPending()) {
|
||||
$event->addAction('invoice.paid', ['url' => $this->path('admin_invoice_status', ['id' => $invoice->getId(), 'status' => 'paid'])]);
|
||||
}
|
||||
|
||||
$event->addAction('download', ['url' => $this->path('admin_invoice_download', ['id' => $invoice->getId()]), 'target' => '_blank']);
|
||||
$event->addDelete($this->path('admin_invoice_delete', ['id' => $invoice->getId()]), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/EventSubscriber/Actions/InvoiceTemplateSubscriber.php
Normal file
42
src/EventSubscriber/Actions/InvoiceTemplateSubscriber.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\InvoiceTemplate;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoiceTemplateSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'invoice_template';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var InvoiceTemplate $template */
|
||||
$template = $payload['template'];
|
||||
|
||||
if ($template->getId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('manage_invoice_template')) {
|
||||
if (!$event->isIndexView()) {
|
||||
$event->addBack($this->path('invoice'));
|
||||
}
|
||||
$event->addAction('edit', ['url' => $this->path('admin_invoice_template_edit', ['id' => $template->getId()]), 'class' => 'modal-ajax-form']);
|
||||
$event->addAction('copy', ['url' => $this->path('admin_invoice_template_copy', ['id' => $template->getId()])]);
|
||||
$event->addDelete($this->path('admin_invoice_template_delete', ['id' => $template->getId()]), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoiceTemplateUploadSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'invoice_upload';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
if ($event->isIndexView() && $this->isGranted('manage_invoice_template')) {
|
||||
$event->addBack($this->path('admin_invoice_template'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('invoices.html'));
|
||||
}
|
||||
}
|
||||
40
src/EventSubscriber/Actions/InvoiceTemplatesSubscriber.php
Normal file
40
src/EventSubscriber/Actions/InvoiceTemplatesSubscriber.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoiceTemplatesSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'invoice_templates';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
if ($this->isGranted('view_invoice')) {
|
||||
$event->addBack($this->path('invoice'));
|
||||
}
|
||||
|
||||
$event->addColumnToggle('#modal_invoice_template');
|
||||
|
||||
if ($this->isGranted('manage_invoice_template')) {
|
||||
$event->addAction('create', ['url' => $this->path('admin_invoice_template_create'), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
// File upload does not work in a modal right now
|
||||
if ($this->isGranted('upload_invoice_template')) {
|
||||
$event->addAction('upload', ['url' => $this->path('admin_invoice_document_upload')]);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('invoices.html'));
|
||||
}
|
||||
}
|
||||
39
src/EventSubscriber/Actions/InvoicesSubscriber.php
Normal file
39
src/EventSubscriber/Actions/InvoicesSubscriber.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class InvoicesSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'invoices';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addColumnToggle('#modal_invoice');
|
||||
|
||||
if ($this->isGranted('history_invoice')) {
|
||||
$event->addAction('list', ['url' => $this->path('admin_invoice_list')]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('manage_invoice_template')) {
|
||||
$event->addAction('invoice-template', ['url' => $this->path('admin_invoice_template')]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('system_configuration')) {
|
||||
$event->addAction('settings', ['url' => $this->path('system_configuration_section', ['section' => 'invoice']), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('invoices.html'));
|
||||
}
|
||||
}
|
||||
34
src/EventSubscriber/Actions/PermissionsSubscriber.php
Normal file
34
src/EventSubscriber/Actions/PermissionsSubscriber.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class PermissionsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'user_permissions';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
// the "create role" page
|
||||
if (!$event->isIndexView() && $this->isGranted('role_permissions')) {
|
||||
//$event->addBack($this->path('admin_user_permissions'));
|
||||
}
|
||||
|
||||
if ($this->isGranted('role_permissions')) {
|
||||
$event->addCreate($this->path('admin_user_roles'), !$event->isView('role'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('permissions.html'));
|
||||
}
|
||||
}
|
||||
31
src/EventSubscriber/Actions/PluginSubscriber.php
Normal file
31
src/EventSubscriber/Actions/PluginSubscriber.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
use App\Plugin\Plugin;
|
||||
|
||||
class PluginSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'plugin';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Plugin $plugin */
|
||||
$plugin = $payload['plugin'];
|
||||
|
||||
$event->addAction('home', ['url' => $plugin->getMetadata()->getHomepage(), 'target' => '_blank']);
|
||||
}
|
||||
}
|
||||
27
src/EventSubscriber/Actions/PluginsSubscriber.php
Normal file
27
src/EventSubscriber/Actions/PluginsSubscriber.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Constants;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class PluginsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'plugins';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addAction('shop', ['url' => Constants::HOMEPAGE . '/store/', 'target' => '_blank']);
|
||||
$event->addHelp($this->documentationLink('plugins.html'));
|
||||
}
|
||||
}
|
||||
75
src/EventSubscriber/Actions/ProjectSubscriber.php
Normal file
75
src/EventSubscriber/Actions/ProjectSubscriber.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Project;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class ProjectSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'project';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Project $project */
|
||||
$project = $payload['project'];
|
||||
|
||||
if ($project->getId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('view', $project)) {
|
||||
$event->addAction('details', ['url' => $this->path('project_details', ['id' => $project->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('edit', $project)) {
|
||||
$class = $event->isView('edit') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('edit', ['url' => $this->path('admin_project_edit', ['id' => $project->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('permissions', $project)) {
|
||||
$class = $event->isView('permissions') ? '' : 'modal-ajax-form';
|
||||
$event->addAction('permissions', ['url' => $this->path('admin_project_permissions', ['id' => $project->getId()]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($event->countActions() > 0) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_activity')) {
|
||||
$event->addActionToSubmenu('filter', 'activity', ['title' => 'activity', 'translation_domain' => 'actions', 'url' => $this->path('admin_activity', ['customers[]' => $project->getCustomer()->getId(), 'projects[]' => $project->getId()])]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_other_timesheet')) {
|
||||
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet', 'translation_domain' => 'actions', 'url' => $this->path('admin_timesheet', ['customers[]' => $project->getCustomer()->getId(), 'projects[]' => $project->getId()])]);
|
||||
}
|
||||
|
||||
if ($event->hasSubmenu('filter')) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if ($project->isVisible() && $project->getCustomer()->isVisible() && $this->isGranted('create_activity')) {
|
||||
$event->addAction('create-activity', ['icon' => 'create', 'url' => $this->path('admin_activity_create_with_project', ['project' => $project->getId()]), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
if ($this->isGranted('edit', $project)) {
|
||||
$event->addAction('copy', ['url' => $this->path('admin_project_duplicate', ['id' => $project->getId()])]);
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $project)) {
|
||||
$event->addAction('trash', ['url' => $this->path('admin_project_delete', ['id' => $project->getId()]), 'class' => 'modal-ajax-form text-red']);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
src/EventSubscriber/Actions/ProjectsSubscriber.php
Normal file
33
src/EventSubscriber/Actions/ProjectsSubscriber.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class ProjectsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'projects';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_project_admin');
|
||||
$event->addQuickExport($this->path('project_export'));
|
||||
|
||||
if ($this->isGranted('create_project')) {
|
||||
$event->addCreate($this->path('admin_project_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('project.html'));
|
||||
}
|
||||
}
|
||||
42
src/EventSubscriber/Actions/ReportingSubscriber.php
Normal file
42
src/EventSubscriber/Actions/ReportingSubscriber.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
use App\Reporting\ReportingService;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
|
||||
class ReportingSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
private $reportingService;
|
||||
|
||||
public function __construct(AuthorizationCheckerInterface $security, UrlGeneratorInterface $urlGenerator, ReportingService $reportingService)
|
||||
{
|
||||
parent::__construct($security, $urlGenerator);
|
||||
$this->reportingService = $reportingService;
|
||||
}
|
||||
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'reporting';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$reports = $this->reportingService->getAvailableReports($event->getUser());
|
||||
|
||||
foreach ($reports as $report) {
|
||||
$event->addActionToSubmenu('reporting', $report->getId(), ['title' => $report->getLabel(), 'translation_domain' => 'reporting', 'url' => $this->path($report->getRoute()), 'class' => 'toolbar-action report-' . $report->getId()]);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('reporting.html'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class SystemConfigurationSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'system_configuration';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addHelp($this->documentationLink('configurations.html'));
|
||||
}
|
||||
}
|
||||
71
src/EventSubscriber/Actions/TagSubscriber.php
Normal file
71
src/EventSubscriber/Actions/TagSubscriber.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Tag;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TagSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'tag';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
$tag = $payload['tag'];
|
||||
$id = null;
|
||||
$name = null;
|
||||
|
||||
if (\is_array($tag)) {
|
||||
// tag can be either and array (on index page => [id, name, color, amount]) ...
|
||||
$id = $tag['id'];
|
||||
$name = $tag['name'];
|
||||
} elseif ($tag instanceof Tag) {
|
||||
// ...or an entity on detail page
|
||||
$id = $tag->getId();
|
||||
$name = $tag->getName();
|
||||
}
|
||||
|
||||
if (!$event->isIndexView() && $this->isGranted('view_tag')) {
|
||||
//$event->addBack($this->path('tags'));
|
||||
}
|
||||
|
||||
if ($id === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('manage_tag')) {
|
||||
$class = ($event->isView('edit') ? '' : 'modal-ajax-form');
|
||||
$event->addAction('edit', ['url' => $this->path('tags_edit', ['id' => $id]), 'class' => $class]);
|
||||
}
|
||||
|
||||
if ($this->isGranted('view_other_timesheet')) {
|
||||
$event->addActionToSubmenu('filter', 'timesheet', ['title' => 'timesheet', 'translation_domain' => 'actions', 'url' => $this->path('admin_timesheet', ['tags' => $name])]);
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete_tag')) {
|
||||
$event->addAction('trash', [
|
||||
'url' => $this->path('delete_tag', ['id' => $id]),
|
||||
'class' => 'api-link',
|
||||
'attr' => [
|
||||
'data-event' => 'kimai.tagDelete kimai.tagUpdate',
|
||||
'data-method' => 'DELETE',
|
||||
'data-question' => 'confirm.delete',
|
||||
'data-msg-error' => 'action.delete.error',
|
||||
'data-msg-success' => 'action.delete.success'
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/EventSubscriber/Actions/TagsSubscriber.php
Normal file
31
src/EventSubscriber/Actions/TagsSubscriber.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TagsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'tags';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
|
||||
if ($this->isGranted('manage_tag')) {
|
||||
$event->addCreate($this->path('tags_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('tags.html'));
|
||||
}
|
||||
}
|
||||
59
src/EventSubscriber/Actions/TeamSubscriber.php
Normal file
59
src/EventSubscriber/Actions/TeamSubscriber.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Entity\Team;
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TeamSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'team';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
/** @var Team $team */
|
||||
$team = $payload['team'];
|
||||
|
||||
if (!$event->isIndexView() && $this->isGranted('view_tag')) {
|
||||
//$event->addBack($this->path('admin_team'));
|
||||
}
|
||||
|
||||
if ($team->getId() === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->isGranted('edit', $team)) {
|
||||
$event->addAction('edit', ['url' => $this->path('admin_team_edit', ['id' => $team->getId()])]);
|
||||
|
||||
if ($this->isGranted('create_team')) {
|
||||
$event->addAction('copy', ['url' => $this->path('team_duplicate', ['id' => $team->getId()])]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $team)) {
|
||||
$event->addAction('trash', [
|
||||
'url' => $this->path('delete_team', ['id' => $team->getId()]),
|
||||
'class' => 'api-link',
|
||||
'attr' => [
|
||||
'data-event' => 'kimai.teamDelete kimai.teamUpdate',
|
||||
'data-method' => 'DELETE',
|
||||
'data-question' => 'confirm.delete',
|
||||
'data-msg-error' => 'action.delete.error',
|
||||
'data-msg-success' => 'action.delete.success'
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/EventSubscriber/Actions/TeamsSubscriber.php
Normal file
31
src/EventSubscriber/Actions/TeamsSubscriber.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TeamsSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'teams';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
|
||||
if ($this->isGranted('create_team')) {
|
||||
$event->addCreate($this->path('admin_team_create'), false);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('teams.html'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetMultiUpdateSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheets_multi_update';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addBack($this->path('timesheet'));
|
||||
$event->addHelp($this->documentationLink('timesheet.html'));
|
||||
}
|
||||
}
|
||||
25
src/EventSubscriber/Actions/TimesheetSubscriber.php
Normal file
25
src/EventSubscriber/Actions/TimesheetSubscriber.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetSubscriber extends AbstractTimesheetSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheet';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$this->timesheetActions($event, 'timesheet', 'timesheet_edit');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetTeamMultiUpdateSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheets_team_multi_update';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addBack($this->path('admin_timesheet'));
|
||||
$event->addHelp($this->documentationLink('timesheet.html'));
|
||||
}
|
||||
}
|
||||
25
src/EventSubscriber/Actions/TimesheetTeamSubscriber.php
Normal file
25
src/EventSubscriber/Actions/TimesheetTeamSubscriber.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetTeamSubscriber extends AbstractTimesheetSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheet_team';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$this->timesheetActions($event, 'admin_timesheet', 'admin_timesheet_edit');
|
||||
}
|
||||
}
|
||||
36
src/EventSubscriber/Actions/TimesheetsSubscriber.php
Normal file
36
src/EventSubscriber/Actions/TimesheetsSubscriber.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetsSubscriber extends AbstractTimesheetsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheets';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_timesheet');
|
||||
|
||||
if ($this->isGranted('export_own_timesheet')) {
|
||||
$this->addExporter($event, 'timesheet_export');
|
||||
}
|
||||
|
||||
if ($this->isGranted('create_own_timesheet')) {
|
||||
$event->addCreate($this->path('timesheet_create'));
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('timesheet.html'));
|
||||
}
|
||||
}
|
||||
37
src/EventSubscriber/Actions/TimesheetsTeamSubscriber.php
Normal file
37
src/EventSubscriber/Actions/TimesheetsTeamSubscriber.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class TimesheetsTeamSubscriber extends AbstractTimesheetsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'timesheets_team';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
$event->addColumnToggle('#modal_timesheet_admin');
|
||||
|
||||
if ($this->isGranted('export_other_timesheet')) {
|
||||
$this->addExporter($event, 'admin_timesheet_export');
|
||||
}
|
||||
|
||||
if ($this->isGranted('create_other_timesheet')) {
|
||||
$event->addActionToSubmenu('create', 'single', ['title' => 'create', 'url' => $this->path('admin_timesheet_create'), 'class' => 'create-ts modal-ajax-form']);
|
||||
$event->addActionToSubmenu('create', 'multi-user', ['title' => 'create-timesheet-multiuser', 'translation_domain' => 'actions', 'url' => $this->path('admin_timesheet_create_multiuser'), 'class' => 'create-ts-mu modal-ajax-form']);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('timesheet.html'));
|
||||
}
|
||||
}
|
||||
@@ -14,21 +14,15 @@ use App\Event\PageActionsEvent;
|
||||
|
||||
class UserSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getSubscribedEvents(): array
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return [
|
||||
'actions.user' => ['onActions', 1000],
|
||||
];
|
||||
return 'user';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event)
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$payload = $event->getPayload();
|
||||
|
||||
if (!isset($payload['user'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var User $user */
|
||||
$user = $payload['user'];
|
||||
|
||||
@@ -36,58 +30,47 @@ class UserSubscriber extends AbstractActionsSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
$actions = $event->getActions();
|
||||
|
||||
if ($this->isGranted('view', $user)) {
|
||||
$actions['profile-stats'] = ['icon' => 'avatar', 'url' => $this->path('user_profile', ['username' => $user->getUsername()]), 'translation_domain' => 'actions'];
|
||||
$event->addAction('profile-stats', ['icon' => 'avatar', 'url' => $this->path('user_profile', ['username' => $user->getUsername()]), 'translation_domain' => 'actions']);
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
if (\count($actions) > 0) {
|
||||
$actions['divider'] = null;
|
||||
}
|
||||
|
||||
$subActions = [];
|
||||
if ($this->isGranted('edit', $user)) {
|
||||
$subActions['edit'] = ['url' => $this->path('user_profile_edit', ['username' => $user->getUsername()]), 'title' => 'edit', 'translation_domain' => 'actions'];
|
||||
$event->addActionToSubmenu('edit', 'edit', ['url' => $this->path('user_profile_edit', ['username' => $user->getUsername()]), 'title' => 'edit', 'translation_domain' => 'actions']);
|
||||
}
|
||||
if ($this->isGranted('preferences', $user)) {
|
||||
$subActions['settings'] = ['url' => $this->path('user_profile_preferences', ['username' => $user->getUsername()]), 'title' => 'settings', 'translation_domain' => 'actions'];
|
||||
$event->addActionToSubmenu('edit', 'settings', ['url' => $this->path('user_profile_preferences', ['username' => $user->getUsername()]), 'title' => 'settings', 'translation_domain' => 'actions']);
|
||||
}
|
||||
if ($this->isGranted('password', $user)) {
|
||||
$subActions['password'] = ['url' => $this->path('user_profile_password', ['username' => $user->getUsername()]), 'title' => 'profile.password'];
|
||||
$event->addActionToSubmenu('edit', 'password', ['url' => $this->path('user_profile_password', ['username' => $user->getUsername()]), 'title' => 'profile.password']);
|
||||
}
|
||||
if ($this->isGranted('api-token', $user)) {
|
||||
$subActions['api-token'] = ['url' => $this->path('user_profile_api_token', ['username' => $user->getUsername()]), 'title' => 'profile.api-token'];
|
||||
$event->addActionToSubmenu('edit', 'api-token', ['url' => $this->path('user_profile_api_token', ['username' => $user->getUsername()]), 'title' => 'profile.api-token']);
|
||||
}
|
||||
if ($this->isGranted('teams', $user)) {
|
||||
$subActions['teams'] = ['url' => $this->path('user_profile_teams', ['username' => $user->getUsername()]), 'title' => 'profile.teams'];
|
||||
$event->addActionToSubmenu('edit', 'teams', ['url' => $this->path('user_profile_teams', ['username' => $user->getUsername()]), 'title' => 'profile.teams']);
|
||||
}
|
||||
if ($this->isGranted('roles', $user)) {
|
||||
$subActions['roles'] = ['url' => $this->path('user_profile_roles', ['username' => $user->getUsername()]), 'title' => 'profile.roles'];
|
||||
$event->addActionToSubmenu('edit', 'roles', ['url' => $this->path('user_profile_roles', ['username' => $user->getUsername()]), 'title' => 'profile.roles']);
|
||||
}
|
||||
|
||||
if (\count($subActions) > 0) {
|
||||
$actions['edit'] = ['children' => $subActions, 'title' => 'edit'];
|
||||
$actions['divider2'] = null;
|
||||
if ($event->hasSubmenu('edit')) {
|
||||
$event->addDivider();
|
||||
}
|
||||
|
||||
$viewOther = $this->isGranted('view_other_timesheet');
|
||||
if ($this->isGranted('view_reporting')) {
|
||||
if ($viewOther || ($event->getUser()->getId() === $user->getId())) {
|
||||
$actions['menu.reporting'] = ['url' => $this->path('report_user_month', ['user' => $user->getId()]), 'icon' => 'reporting'];
|
||||
$event->addAction('menu.reporting', ['url' => $this->path('report_user_month', ['user' => $user->getId()]), 'icon' => 'reporting']);
|
||||
}
|
||||
}
|
||||
|
||||
if ($viewOther && $user->isEnabled()) {
|
||||
$actions['timesheet'] = $this->path('admin_timesheet', ['users[]' => $user->getId()]);
|
||||
$event->addAction('timesheet', ['url' => $this->path('admin_timesheet', ['users[]' => $user->getId()])]);
|
||||
}
|
||||
|
||||
$view = $payload['view'] ?? null;
|
||||
|
||||
if ($view === 'index' && $this->isGranted('delete', $user)) {
|
||||
$actions['trash'] = ['url' => $this->path('admin_user_delete', ['id' => $user->getId()]), 'class' => 'modal-ajax-form'];
|
||||
if ($event->isIndexView() && $this->isGranted('delete', $user)) {
|
||||
$event->addAction('trash', ['url' => $this->path('admin_user_delete', ['id' => $user->getId()]), 'class' => 'modal-ajax-form']);
|
||||
}
|
||||
|
||||
$event->setActions($actions);
|
||||
}
|
||||
}
|
||||
|
||||
35
src/EventSubscriber/Actions/UsersSubscriber.php
Normal file
35
src/EventSubscriber/Actions/UsersSubscriber.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?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\Actions;
|
||||
|
||||
use App\Event\PageActionsEvent;
|
||||
|
||||
class UsersSubscriber extends AbstractActionsSubscriber
|
||||
{
|
||||
public static function getActionName(): string
|
||||
{
|
||||
return 'users';
|
||||
}
|
||||
|
||||
public function onActions(PageActionsEvent $event): void
|
||||
{
|
||||
$event->addSearchToggle();
|
||||
if ($event->isIndexView()) {
|
||||
$event->addColumnToggle('#modal_user_admin');
|
||||
}
|
||||
$event->addQuickExport($this->path('user_export'));
|
||||
|
||||
if ($this->isGranted('create_user')) {
|
||||
$event->addCreate($this->path('admin_user_create'), false);
|
||||
}
|
||||
|
||||
$event->addHelp($this->documentationLink('users.html'));
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ final class UserPreferenceSubscriber implements EventSubscriberInterface
|
||||
$timezone = date_default_timezone_get();
|
||||
}
|
||||
|
||||
$enableDefaultReport = $this->voter->isGranted('view_reporting');
|
||||
$enableHourlyRate = false;
|
||||
$hourlyRateOptions = [];
|
||||
|
||||
@@ -151,6 +152,7 @@ final class UserPreferenceSubscriber implements EventSubscriberInterface
|
||||
->setValue(ReportingService::DEFAULT_VIEW)
|
||||
->setOrder(650)
|
||||
->setSection('behaviour')
|
||||
->setEnabled($enableDefaultReport)
|
||||
->setType(ReportType::class),
|
||||
|
||||
(new UserPreference())
|
||||
|
||||
@@ -34,9 +34,9 @@ final class ProjectViewModel
|
||||
*/
|
||||
private $durationTotal = 0;
|
||||
/**
|
||||
* @var int
|
||||
* @var float
|
||||
*/
|
||||
private $rateTotal = 0;
|
||||
private $rateTotal = 0.00;
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
@@ -116,12 +116,12 @@ final class ProjectViewModel
|
||||
$this->notExportedRate = $notExportedRate;
|
||||
}
|
||||
|
||||
public function getRateTotal(): int
|
||||
public function getRateTotal(): float
|
||||
{
|
||||
return $this->rateTotal;
|
||||
}
|
||||
|
||||
public function setRateTotal(int $rateTotal): void
|
||||
public function setRateTotal(float $rateTotal): void
|
||||
{
|
||||
$this->rateTotal = $rateTotal;
|
||||
}
|
||||
|
||||
@@ -52,8 +52,15 @@ final class ProjectViewService
|
||||
->leftJoin(Timesheet::class, 't', 'WITH', 'p.id = t.project')
|
||||
->andWhere($qb->expr()->eq('p.visible', true))
|
||||
->andWhere($qb->expr()->eq('c.visible', true))
|
||||
->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->isNull('p.end'),
|
||||
$qb->expr()->gte('p.end', ':project_end')
|
||||
)
|
||||
)
|
||||
->addGroupBy('p')
|
||||
->addGroupBy('t.project')
|
||||
->setParameter('project_end', $today, Types::DATETIME_MUTABLE)
|
||||
;
|
||||
|
||||
if ($query->getCustomer() !== null) {
|
||||
@@ -68,8 +75,8 @@ final class ProjectViewService
|
||||
if (!$query->isIncludeNoBudget()) {
|
||||
$qb->andWhere(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->gt('p.budget', 0),
|
||||
$qb->expr()->gt('p.timeBudget', 0)
|
||||
$qb->expr()->gt('p.timeBudget', 0),
|
||||
$qb->expr()->gt('p.budget', 0)
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -83,7 +90,7 @@ final class ProjectViewService
|
||||
$entity = new ProjectViewModel();
|
||||
$entity->setProject($res['project']);
|
||||
$entity->setDurationTotal($res['totalDuration'] ?? 0);
|
||||
$entity->setRateTotal($res['totalRate'] ?? 0);
|
||||
$entity->setRateTotal($res['totalRate'] ?? 0.00);
|
||||
|
||||
$projectViews[$entity->getProject()->getId()] = $entity;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ final class IconExtension extends AbstractExtension
|
||||
'dashboard' => 'fas fa-tachometer-alt',
|
||||
'debug' => 'far fa-file-alt',
|
||||
'delete' => 'far fa-trash-alt',
|
||||
'details' => 'fas fa-info-circle',
|
||||
'doctor' => 'fas fa-medkit',
|
||||
'dot' => 'fas fa-circle',
|
||||
'download' => 'fas fa-download',
|
||||
|
||||
@@ -1,36 +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\Twig\Runtime;
|
||||
|
||||
use App\Export\ServiceExport;
|
||||
use Twig\Extension\RuntimeExtensionInterface;
|
||||
|
||||
final class ExporterExtension implements RuntimeExtensionInterface
|
||||
{
|
||||
/**
|
||||
* @var ServiceExport
|
||||
*/
|
||||
private $service;
|
||||
|
||||
public function __construct(ServiceExport $service)
|
||||
{
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function getTimesheetExporter(): array
|
||||
{
|
||||
$ids = [];
|
||||
foreach ($this->service->getTimesheetExporter() as $exporter) {
|
||||
$ids[] = $exporter->getId();
|
||||
}
|
||||
|
||||
return $ids;
|
||||
}
|
||||
}
|
||||
@@ -52,13 +52,9 @@ final class ThemeExtension implements RuntimeExtensionInterface
|
||||
return $themeEvent;
|
||||
}
|
||||
|
||||
public function actions(User $user, string $action, array $payload): ThemeEvent
|
||||
public function actions(User $user, string $action, string $view, array $payload = []): ThemeEvent
|
||||
{
|
||||
if (!\array_key_exists('actions', $payload)) {
|
||||
$payload['actions'] = [];
|
||||
}
|
||||
|
||||
$themeEvent = new PageActionsEvent($user, $payload, $action);
|
||||
$themeEvent = new PageActionsEvent($user, $payload, $action, $view);
|
||||
|
||||
$eventName = 'actions.' . $action;
|
||||
|
||||
|
||||
@@ -10,9 +10,7 @@
|
||||
namespace App\Twig;
|
||||
|
||||
use App\Twig\Runtime\EncoreExtension;
|
||||
use App\Twig\Runtime\ExporterExtension;
|
||||
use App\Twig\Runtime\MarkdownExtension;
|
||||
use App\Twig\Runtime\ReportingExtension;
|
||||
use App\Twig\Runtime\ThemeExtension;
|
||||
use App\Twig\Runtime\TimesheetExtension;
|
||||
use App\Twig\Runtime\WidgetExtension;
|
||||
@@ -31,11 +29,9 @@ class RuntimeExtensions extends AbstractExtension
|
||||
new TwigFunction('trigger', [ThemeExtension::class, 'trigger'], ['needs_environment' => true]),
|
||||
new TwigFunction('actions', [ThemeExtension::class, 'actions']),
|
||||
new TwigFunction('javascript_translations', [ThemeExtension::class, 'getJavascriptTranslations']),
|
||||
new TwigFunction('timesheet_exporter', [ExporterExtension::class, 'getTimesheetExporter']),
|
||||
new TwigFunction('active_timesheets', [TimesheetExtension::class, 'activeEntries']),
|
||||
new TwigFunction('encore_entry_css_source', [EncoreExtension::class, 'getEncoreEntryCssSource']),
|
||||
new TwigFunction('render_widget', [WidgetExtension::class, 'renderWidget'], ['is_safe' => ['html']]),
|
||||
new TwigFunction('available_reports', [ReportingExtension::class, 'getAvailableReports'], []),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
{% macro about(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
{% set event = trigger('actions.about', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'about', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,64 +1,15 @@
|
||||
{% macro activities(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}, 'visibility': '#modal_activity_admin'} %}
|
||||
|
||||
{% set actions = actions|merge({'download': {'url': path('activity_export'), 'class': 'toolbar-action'}}) %}
|
||||
|
||||
{% if is_granted('create_activity') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_activity_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'activity.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.activities', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'activities', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro activity(activity, view, options) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if activity.id is not empty %}
|
||||
{% if view != 'details' and is_granted('view', activity) %}
|
||||
{% set actions = actions|merge({'details': path('activity_details', {'id': activity.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('edit', activity) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_activity_edit', {'id': activity.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('permissions', activity) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'permissions' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'permissions': {'url': path('admin_activity_permissions', {'id': activity.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_other_timesheet') %}
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'customers[]': activity.project ? activity.project.customer.id : null, 'projects[]': activity.project ? activity.project.id : null, 'activities[]': activity.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('create_other_timesheet') %}
|
||||
{% set actions = actions|merge({'create-timesheet': {'url': path('admin_timesheet_create', {'project': activity.project ? activity.project.id : null, 'activity': activity.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% if (view == 'index' or view == 'custom') and is_granted('delete', activity) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_activity_delete', {'id': activity.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' and view != 'custom' %}
|
||||
{% set actions = actions|merge({'back': options.back|default(path('admin_activity'))}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.activity', {'actions': actions, 'view': view, 'activity': activity}) %}
|
||||
{% set event = actions(app.user, 'activity', view, {'activity': activity}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
{% block main %}
|
||||
{{ include(app.request.xmlHttpRequest ? 'default/_form_modal.html.twig' : 'default/_form.html.twig', {
|
||||
'title': activity.name,
|
||||
'title': ('permissions'|trans({}, 'actions')) ~ ': ' ~ activity.name,
|
||||
'form': form,
|
||||
'back': path('admin_activity')
|
||||
'back': path('activity_details', {'id': activity.id})
|
||||
}) }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
{% macro calendar(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% if is_granted('create_own_timesheet') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('timesheet_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.calendar', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endmacro %}
|
||||
@@ -1,9 +1,12 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "calendar/actions.html.twig" as actions %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% block page_title %}{{ 'calendar.title'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.calendar('index') }}{% endblock %}
|
||||
{% block page_actions %}
|
||||
{% set event = actions(app.user, 'calendar', 'index') %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
|
||||
@@ -1,72 +1,15 @@
|
||||
{% macro customers(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {
|
||||
'search': {'class': 'search-toggle visible-xs-inline'},
|
||||
'visibility': {'modal': '#modal_customer_admin'},
|
||||
'download': {'url': path('customer_export'), 'class': 'toolbar-action'}
|
||||
} %}
|
||||
|
||||
{% if is_granted('create_customer') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_customer_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'customer.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.customers', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'customers', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro customer(customer, view, options) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if customer.id is not empty %}
|
||||
{% if view != 'details' and is_granted('view', customer) %}
|
||||
{% set actions = actions|merge({'details': path('customer_details', {'id': customer.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('edit', customer) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_customer_edit', {'id': customer.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('permissions', customer) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'permissions' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'permissions': {'url': path('admin_customer_permissions', {'id': customer.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_project') or is_granted('view_teamlead_project') or is_granted('view_team_project') %}
|
||||
{% set actions = actions|merge({'project': path('admin_project', {'customers[]': customer.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_activity') %}
|
||||
{% set actions = actions|merge({'activity': path('admin_activity', {'customers[]': customer.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_other_timesheet') %}
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'customers[]': customer.id})}) %}
|
||||
{% endif %}
|
||||
{% if customer.visible and is_granted('create_project') %}
|
||||
{% set actions = actions|merge({'create-project': {'url': path('admin_project_create_with_customer', {'customer': customer.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% if view == 'index' and is_granted('delete', customer) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_customer_delete', {'id': customer.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' and view != 'custom' %}
|
||||
{% set actions = actions|merge({'back': options.back|default(path('admin_customer'))}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.customer', {'actions': actions, 'view': view, 'customer': customer}) %}
|
||||
{% set event = actions(app.user, 'customer', view, {'customer': customer}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
{% block main %}
|
||||
{{ include(app.request.xmlHttpRequest ? 'default/_form_modal.html.twig' : 'default/_form.html.twig', {
|
||||
'title': customer.name,
|
||||
'title': ('permissions'|trans({}, 'actions')) ~ ': ' ~ customer.name,
|
||||
'form': form,
|
||||
'back': path('admin_customer')
|
||||
'back': path('customer_details', {'id': customer.id})
|
||||
}) }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{% macro doctor(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% set event = trigger('actions.doctor', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endmacro %}
|
||||
@@ -1,9 +1,12 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "doctor/actions.html.twig" as actions %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% block page_title %}{{ 'menu.doctor'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}Environment: {{ environment }} – Version: {{ constant('App\\Constants::VERSION') }} {{ constant('App\\Constants::STATUS') }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.doctor('index') }}{% endblock %}
|
||||
{% block page_actions %}
|
||||
{% set event = actions(app.user, 'doctor', 'index') %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
@@ -158,4 +161,5 @@
|
||||
</table>
|
||||
{% endblock %}
|
||||
{% endembed %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
{% macro export(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'visibility': '#modal_export'} %}
|
||||
|
||||
{% if view == 'preview' %}
|
||||
{% set actions = actions|merge({'off': {'id':'export-toggle-button'}}) %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'help': {'url': 'export.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.export', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endmacro %}
|
||||
@@ -2,7 +2,6 @@
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "macros/toolbar.html.twig" as toolbar %}
|
||||
{% import "macros/datatables.html.twig" as tables %}
|
||||
{% import "export/actions.html.twig" as actions %}
|
||||
|
||||
{% set columns = {
|
||||
'date': {'class': 'alwaysVisible text-nowrap', 'orderBy': false},
|
||||
@@ -21,7 +20,10 @@
|
||||
|
||||
{% block page_title %}{{ 'export.title'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'export.subtitle'|trans }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.export((preview_show ? 'preview' : 'index')) }}{% endblock %}
|
||||
{% block page_actions %}
|
||||
{% set event = actions(app.user, 'export', (preview_show ? 'preview' : 'index')) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main_before %}
|
||||
{{ tables.data_table_column_modal(tableName, columns) }}
|
||||
|
||||
@@ -1,111 +1,35 @@
|
||||
|
||||
{% macro invoices(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'visibility': '#modal_invoice'} %}
|
||||
|
||||
{% if is_granted('history_invoice') %}
|
||||
{% set actions = actions|merge({'list': path('admin_invoice_list')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'invoice-template': path('admin_invoice_template')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('system_configuration') %}
|
||||
{% set actions = actions|merge({'settings': {'url': path('system_configuration_section', {'section': 'invoice'}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'invoices.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.invoices', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'invoices', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_templates(view) %}
|
||||
{% macro invoice(invoice, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% if is_granted('view_invoice') %}
|
||||
{% set actions = actions|merge({'back': path('invoice')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'visibility': '#modal_invoice_template'}) %}
|
||||
|
||||
{% if is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_invoice_template_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('upload_invoice_template') %}
|
||||
{# File upload does not work in a modal right now #}
|
||||
{% set actions = actions|merge({'upload': {'url': path('admin_invoice_document_upload')}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'invoices.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.invoice_templates', {'actions': actions, 'view': 'index'}) %}
|
||||
{{ widgets.page_actions(actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice(invoice, view, options) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if is_granted('history_invoice') %}
|
||||
{% if invoice.new %}
|
||||
{% set actions = actions|merge({'invoice.pending': path('admin_invoice_status', {'id': invoice.id, 'status': 'pending'})}) %}
|
||||
{% elseif invoice.pending %}
|
||||
{% set actions = actions|merge({'invoice.paid': path('admin_invoice_status', {'id': invoice.id, 'status': 'paid'})}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'download': {'url': path('admin_invoice_download', {'id': invoice.id}), 'target': '_blank'}}) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_invoice_delete', {'id' : invoice.id}), 'class': 'confirmation-link', 'attr': {'data-question': 'confirm.delete'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if options.back is defined %}
|
||||
{% set actions = actions|merge({'back': options.back}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.invoice', {'actions': actions, 'invoice': invoice}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% set event = actions(app.user, 'invoice', view, {'invoice': invoice}) %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_listing(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set event = actions(app.user, 'invoice_details', {'view': view}) %}
|
||||
{% set event = actions(app.user, 'invoice_details', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_upload(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set event = actions(app.user, 'invoice_upload', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% if view == 'index' and is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'back': path('admin_invoice_template')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'invoices.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.invoice_upload', {'actions': actions, 'view': 'index'}) %}
|
||||
{{ widgets.page_actions(actions) }}
|
||||
{% macro invoice_templates(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set event = actions(app.user, 'invoice_templates', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro invoice_template(template, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if is_granted('manage_invoice_template') %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_invoice_template_edit', {'id' : template.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% set actions = actions|merge({'copy': path('admin_invoice_template_copy', {'id' : template.id})}) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_invoice_template_delete', {'id' : template.id}), 'class': 'confirmation-link', 'attr': {'data-question': 'confirm.delete'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.invoice_template', {'actions': actions, 'view': view, 'template': template}) %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'invoice_template', view, {'template': template}) %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
{% macro user_permissions(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if view != 'index' and is_granted('role_permissions') %}
|
||||
{% set actions = actions|merge({'permissions': path('admin_user_permissions')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'role' and is_granted('role_permissions') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_user_roles'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'permissions.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.user_permissions', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'user_permissions', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{% macro plugins(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'shop': {'url': constant('App\\Constants::HOMEPAGE') ~ '/store/', 'target': '_blank'}} %}
|
||||
{% set actions = actions|merge({'help': {'url': 'plugins.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.plugins', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro plugin(plugin, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'home': {'url': plugin.metadata.homepage, 'target': '_blank'}} %}
|
||||
|
||||
{% set event = trigger('actions.plugin', {'actions': actions, 'view': view, 'plugin': plugin}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
@@ -1,11 +1,13 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "plugin/actions.html.twig" as actions %}
|
||||
{% import "macros/datatables.html.twig" as tables %}
|
||||
|
||||
{% block page_title %}{{ 'plugins.title'|trans({}, 'plugins') }}{% endblock %}
|
||||
{% block page_subtitle %}{{ 'plugins.subtitle'|trans({}, 'plugins') }}{% endblock %}
|
||||
{% block page_actions %}{{ actions.plugins('index') }}{% endblock %}
|
||||
{% block page_actions %}
|
||||
{% set event = actions(app.user, 'plugins', 'index') %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
||||
@@ -45,7 +47,8 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="{{ tables.data_table_column_class(tableName, columns, 'actions') }}">
|
||||
{{ actions.plugin(plugin, 'index') }}
|
||||
{% set event = actions(app.user, 'plugin', 'index', {'plugin': plugin}) %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
@@ -1,68 +1,15 @@
|
||||
{% macro projects(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}, 'visibility': '#modal_project_admin'} %}
|
||||
|
||||
{% set actions = actions|merge({'download': {'url': path('project_export'), 'class': 'toolbar-action'}}) %}
|
||||
|
||||
{% if is_granted('create_project') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_project_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'project.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.projects', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'projects', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro project(project, view, options) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if project.id is not empty %}
|
||||
{% if view != 'details' and is_granted('view', project) %}
|
||||
{% set actions = actions|merge({'details': path('project_details', {'id': project.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('edit', project) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_project_edit', {'id': project.id}), 'class': class}}) %}
|
||||
{% set actions = actions|merge({'copy': {'url': path('admin_project_duplicate', {'id': project.id})}}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('permissions', project) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'permissions' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'permissions': {'url': path('admin_project_permissions', {'id': project.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_activity') %}
|
||||
{% set actions = actions|merge({'activity': path('admin_activity', {'customers[]': project.customer.id, 'projects[]': project.id})}) %}
|
||||
{% endif %}
|
||||
{% if is_granted('view_other_timesheet') %}
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'customers[]': project.customer.id, 'projects[]': project.id})}) %}
|
||||
{% endif %}
|
||||
{% if project.visible and project.customer.visible and is_granted('create_activity') %}
|
||||
{% set actions = actions|merge({'create-activity': {'url': path('admin_activity_create_with_project', {'project': project.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% if (view == 'index' or view == 'custom') and is_granted('delete', project) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('admin_project_delete', {'id': project.id}), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' and view != 'custom' %}
|
||||
{% set actions = actions|merge({'back': options.back|default(path('admin_project'))}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.project', {'actions': actions, 'view': view, 'project': project}) %}
|
||||
{% set event = actions(app.user, 'project', view, {'project': project}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
{% block main %}
|
||||
{{ include(app.request.xmlHttpRequest ? 'default/_form_modal.html.twig' : 'default/_form.html.twig', {
|
||||
'title': project.name,
|
||||
'title': ('permissions'|trans({}, 'actions')) ~ ': ' ~ project.name,
|
||||
'form': form,
|
||||
'back': path('admin_project')
|
||||
'back': path('project_details', {'id': project.id})
|
||||
}) }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
{% macro reporting() %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
{% set children = {} %}
|
||||
{% for id, report in available_reports(app.user) %}
|
||||
{% set children = children|merge({(report.id): {'title': report.label|trans({}, 'reporting'), 'url': path(report.route), 'class': 'toolbar-action report-' ~ report.id}}) %}
|
||||
{% endfor %}
|
||||
{% set actions = actions|merge({'reporting': {'children': children}}) %}
|
||||
{% set actions = actions|merge({'help': {'url': 'reporting.html'|docu_link, 'target': '_blank'}}) %}
|
||||
{% set event = trigger('actions.reporting', {'actions': actions}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% endmacro %}
|
||||
@@ -1,9 +1,12 @@
|
||||
{% extends 'base.html.twig' %}
|
||||
{% import "reporting/actions.html.twig" as actions %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% block page_title %}{{ 'menu.reporting'|trans }}{% endblock %}
|
||||
{% block page_subtitle %}{% block report_title %}{% endblock %}{% endblock %}
|
||||
{% block page_actions %}{{ actions.reporting() }}{% endblock %}
|
||||
{% block page_actions %}
|
||||
{% set event = actions(app.user, 'reporting', 'index') %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="row">
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
{% macro system_configuration(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% set actions = actions|merge({'help': {'url': 'configurations.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.system_configuration', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'system_configuration', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,49 +1,15 @@
|
||||
{% macro tags(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}} %}
|
||||
|
||||
{% if is_granted('manage_tag') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('tags_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'tags.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.tags', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'tags', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro tag(tag, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if tag.id is not empty %}
|
||||
{% if is_granted('manage_tag') %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('tags_edit', {'id': tag.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('view_other_timesheet') %}
|
||||
{% set actions = actions|merge({'timesheet': path('admin_timesheet', {'tags': tag.name})}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('delete_tag') %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('delete_tag', {'id' : tag.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.tagDelete kimai.tagUpdate', 'data-method': 'DELETE', 'data-question': 'confirm.delete', 'data-msg-error': 'action.delete.error', 'data-msg-success': 'action.delete.success'}}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'back': path('tags')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.tag', {'actions': actions, 'view': view, 'tag': tag}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'tag', view, {'tag': tag}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,40 +1,15 @@
|
||||
{% macro teams(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}} %}
|
||||
|
||||
{% if is_granted('create_team') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_team_create')}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'teams.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.teams', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'teams', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro team(team, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% if team.id is not empty %}
|
||||
{% if is_granted('edit', team) %}
|
||||
{% set class = '' %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_team_edit', {'id': team.id}), 'class': class}}) %}
|
||||
{% if is_granted('create_team') %}
|
||||
{% set actions = actions|merge({'copy': {'url': path('team_duplicate', {'id': team.id})}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view == 'index' and is_granted('delete', team) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('delete_team', {'id' : team.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.teamDelete kimai.teamUpdate', 'data-method': 'DELETE', 'data-question': 'confirm.delete', 'data-msg-error': 'action.delete.error', 'data-msg-success': 'action.delete.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.team', {'actions': actions, 'view': view, 'team': team}) %}
|
||||
{% set event = actions(app.user, 'team', view, {'team': team}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,83 +1,21 @@
|
||||
{% macro timesheets_team(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}} %}
|
||||
{% if is_granted('export_own_timesheet') %}
|
||||
{% set exporterIds = timesheet_exporter() %}
|
||||
{% if exporterIds|length == 1 %}
|
||||
{% set actions = actions|merge({'download': {'url': path('admin_timesheet_export', {'exporter': exporterIds.0}), 'class': 'toolbar-action'}}) %}
|
||||
{% elseif exporterIds|length > 1 %}
|
||||
{% set children = {} %}
|
||||
{% for exporter in exporterIds %}
|
||||
{% set children = children|merge({(exporter): {'title': ('button.' ~ exporter)|trans, 'url': path('admin_timesheet_export', {'exporter': exporter}), 'class': 'toolbar-action exporter-' ~ exporter}}) %}
|
||||
{% endfor %}
|
||||
{% set actions = actions|merge({'download': {'children': children}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'visibility': '#modal_timesheet_admin'}) %}
|
||||
{% if is_granted('create_other_timesheet') %}
|
||||
{% set actions = actions|merge({'create': {'children': {'single': {'title': 'create'|trans,'url': path('admin_timesheet_create'), 'class': 'create-ts modal-ajax-form'}, 'multi-user': {'title': 'create-timesheet-multiuser'|trans({}, 'actions'),'url': path('admin_timesheet_create_multiuser'), 'class': 'create-ts-mu modal-ajax-form'}}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'timesheet.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.timesheets_team', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'timesheets_team', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro timesheet_team(timesheet, view, options) %}
|
||||
{% macro timesheet_team(timesheet, view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if timesheet.id is not empty %}
|
||||
{% if not timesheet.end and is_granted('stop', timesheet) %}
|
||||
{% set actions = actions|merge({'stop': {'url': path('stop_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.timesheetStop kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'timesheet.stop.error', 'data-msg-success': 'timesheet.stop.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if timesheet.end and is_granted('start', timesheet) %}
|
||||
{% set actions = actions|merge({'repeat': {'url': path('restart_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-payload': '{"copy": "all"}', 'data-event': 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'timesheet.start.error', 'data-msg-success': 'timesheet.start.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('duplicate', timesheet) %}
|
||||
{% set actions = actions|merge({'copy': {'url': path('duplicate_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-payload': '{"copy": "all"}', 'data-event': 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'action.update.error', 'data-msg-success': 'action.update.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('edit', timesheet) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('admin_timesheet_edit', {'id': timesheet.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if view == 'index' and is_granted('delete', timesheet) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('delete_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.timesheetDelete kimai.timesheetUpdate', 'data-method': 'DELETE', 'data-question': 'confirm.delete', 'data-msg-error': 'action.delete.error', 'data-msg-success': 'action.delete.success'}}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' %}
|
||||
{% set actions = actions|merge({'back': options.back|default(path('admin_timesheet'))}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.timesheet_team', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'timesheet_team', view, {'timesheet': timesheet}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro timesheets_team_multi_update(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% set actions = actions|merge({'back': path('admin_timesheet')}) %}
|
||||
{% set actions = actions|merge({'help': {'url': 'timesheet.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.timesheets_team_multi_update', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'timesheets_team_multi_update', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,85 +1,21 @@
|
||||
{% macro timesheets(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}} %}
|
||||
{% if is_granted('export_own_timesheet') %}
|
||||
{% set exporterIds = timesheet_exporter() %}
|
||||
{% if exporterIds|length == 1 %}
|
||||
{% set actions = actions|merge({'download': {'url': path('timesheet_export', {'exporter': exporterIds.0}), 'class': 'toolbar-action'}}) %}
|
||||
{% elseif exporterIds|length > 1 %}
|
||||
{% set children = {} %}
|
||||
{% for exporter in exporterIds %}
|
||||
{% set children = children|merge({(exporter): {'title': ('button.' ~ exporter)|trans, 'url': path('timesheet_export', {'exporter': exporter}), 'class': 'toolbar-action exporter-' ~ exporter}}) %}
|
||||
{% endfor %}
|
||||
{% set actions = actions|merge({'download': {'children': children}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'visibility': {'modal': '#modal_timesheet'}}) %}
|
||||
{% if is_granted('create_own_timesheet') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('timesheet_create'), 'class': 'modal-ajax-form'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'timesheet.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.timesheets', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'timesheets', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro timesheet(timesheet, view, options) %}
|
||||
{%- apply spaceless -%}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set actions = {} %}
|
||||
|
||||
{% if timesheet.id is not empty %}
|
||||
{% if not timesheet.end and is_granted('stop', timesheet) %}
|
||||
{% set actions = actions|merge({'stop': {'url': path('stop_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.timesheetStop kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'timesheet.stop.error', 'data-msg-success': 'timesheet.stop.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if timesheet.end and is_granted('start', timesheet) %}
|
||||
{% set actions = actions|merge({'repeat': {'url': path('restart_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-payload': '{"copy": "all"}', 'data-event': 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'timesheet.start.error', 'data-msg-success': 'timesheet.start.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('duplicate', timesheet) %}
|
||||
{% set actions = actions|merge({'copy': {'url': path('duplicate_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-payload': '{"copy": "all"}', 'data-event': 'kimai.timesheetStart kimai.timesheetUpdate', 'data-method': 'PATCH', 'data-msg-error': 'action.update.error', 'data-msg-success': 'action.update.success'}}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if is_granted('edit', timesheet) %}
|
||||
{% set class = '' %}
|
||||
{% if view != 'edit' %}
|
||||
{% set class = 'modal-ajax-form' %}
|
||||
{% endif %}
|
||||
{% set actions = actions|merge({'edit': {'url': path('timesheet_edit', {'id': timesheet.id}), 'class': class}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if actions|length > 0 %}
|
||||
{% set actions = actions|merge({'divider': null}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if view == 'index' and is_granted('delete', timesheet) %}
|
||||
{% set actions = actions|merge({'trash': {'url': path('delete_timesheet', {'id' : timesheet.id}), 'class': 'api-link', 'attr': {'data-event': 'kimai.timesheetDelete kimai.timesheetUpdate', 'data-method': 'DELETE', 'data-question': 'confirm.delete', 'data-msg-error': 'action.delete.error', 'data-msg-success': 'action.delete.success'}}}) %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if view != 'index' and view != 'custom' %}
|
||||
{% set actions = actions|merge({'back': options.back|default(path('timesheet'))}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set event = trigger('actions.timesheet', {'actions': actions, 'view': view, 'timesheet': timesheet}) %}
|
||||
{% set event = actions(app.user, 'timesheet', view, {'timesheet': timesheet}) %}
|
||||
{% if view == 'index' or view == 'custom' %}
|
||||
{{ widgets.table_actions(event.payload.actions) }}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
{{ widgets.entity_actions(event.payload.actions) }}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endif %}
|
||||
{%- endapply -%}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro timesheets_multi_update(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {} %}
|
||||
{% set actions = actions|merge({'back': path('timesheet')}) %}
|
||||
{% set actions = actions|merge({'help': {'url': 'timesheet.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.timesheets_multi_update', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'timesheets_multi_update', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -1,30 +1,7 @@
|
||||
{% macro users(view) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
|
||||
{% set actions = {'search': {'class': 'search-toggle visible-xs-inline'}} %}
|
||||
|
||||
{% if view == 'index' %}
|
||||
{% set actions = actions|merge({'visibility': '#modal_user_admin'}) %}
|
||||
{% else %}
|
||||
{% set actions = actions|merge({'back': path('admin_user')}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'download': {'url': path('user_export'), 'class': 'toolbar-action'}}) %}
|
||||
|
||||
{% if is_granted('create_user') %}
|
||||
{% set actions = actions|merge({'create': {'url': path('admin_user_create')}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% if view == 'index' %}
|
||||
{% set actions = actions|merge({'help': {'url': 'users.html'|docu_link, 'target': '_blank'}}) %}
|
||||
{% elseif view == 'permissions' %}
|
||||
{% set actions = actions|merge({'help': {'url': 'permissions.html'|docu_link, 'target': '_blank'}}) %}
|
||||
{% endif %}
|
||||
|
||||
{% set actions = actions|merge({'help': {'url': 'users.html'|docu_link, 'target': '_blank'}}) %}
|
||||
|
||||
{% set event = trigger('actions.users', {'actions': actions, 'view': view}) %}
|
||||
{{ widgets.page_actions(event.payload.actions) }}
|
||||
{% set event = actions(app.user, 'users', view) %}
|
||||
{{ widgets.page_actions(event.actions) }}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro user_permissions(view) %}
|
||||
@@ -35,7 +12,7 @@
|
||||
|
||||
{% macro user(user, view, options) %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% set event = actions(app.user, 'user', {'view': view, 'user': user}) %}
|
||||
{% set event = actions(app.user, 'user', view, {'user': user}) %}
|
||||
{% if view == 'index' %}
|
||||
{{ widgets.table_actions(event.actions) }}
|
||||
{% else %}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-3 col-md-3 col-lg-2">
|
||||
<div class="hidden-xs">
|
||||
{% set event = actions(app.user, 'user', {'view': tab, 'user': user}) %}
|
||||
{% set event = actions(app.user, 'user', tab, {'user': user}) %}
|
||||
{{ widgets.list_group_actions(event.actions, app.request.requestUri) }}
|
||||
</div>
|
||||
{% block profile_navbar %}{% endblock %}
|
||||
|
||||
@@ -263,9 +263,7 @@ class ActivityControllerTest extends ControllerBaseTest
|
||||
$team2->tick();
|
||||
|
||||
$client->submit($form);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/activity/' . $id . '/details'));
|
||||
|
||||
/** @var Activity $activity */
|
||||
$activity = $em->getRepository(Activity::class)->find($id);
|
||||
|
||||
@@ -344,9 +344,7 @@ class CustomerControllerTest extends ControllerBaseTest
|
||||
$team2->tick();
|
||||
|
||||
$client->submit($form);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/customer/1/details'));
|
||||
|
||||
/** @var Customer $customer */
|
||||
$customer = $em->getRepository(Customer::class)->find(1);
|
||||
|
||||
@@ -410,9 +410,7 @@ class ProjectControllerTest extends ControllerBaseTest
|
||||
$team2->tick();
|
||||
|
||||
$client->submit($form);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/project/'));
|
||||
$client->followRedirect();
|
||||
$this->assertHasDataTable($client);
|
||||
$this->assertIsRedirect($client, $this->createUrl('/admin/project/1/details'));
|
||||
|
||||
/** @var Project $project */
|
||||
$project = $em->getRepository(Project::class)->find(1);
|
||||
|
||||
@@ -23,22 +23,104 @@ class PageActionsEventTest extends TestCase
|
||||
$user = new User();
|
||||
$user->setAlias('foo');
|
||||
|
||||
$sut = new PageActionsEvent($user, [], 'foo');
|
||||
$sut = new PageActionsEvent($user, [], 'foo', 'bar');
|
||||
$this->assertEquals('bar', $sut->getView());
|
||||
$this->assertEquals('foo', $sut->getActionName());
|
||||
$this->assertTrue($sut->isView('bar'));
|
||||
$this->assertFalse($sut->isView('foo'));
|
||||
$this->assertFalse($sut->isIndexView());
|
||||
$this->assertSame($user, $sut->getUser());
|
||||
$this->assertEquals([], $sut->getActions());
|
||||
$this->assertEquals(['actions' => []], $sut->getPayload());
|
||||
$this->assertEquals(['actions' => [], 'view' => 'bar'], $sut->getPayload());
|
||||
|
||||
$sut = new PageActionsEvent($user, ['hello' => 'world'], 'foo');
|
||||
$sut = new PageActionsEvent($user, ['hello' => 'world'], 'foo', 'bar');
|
||||
$this->assertSame($user, $sut->getUser());
|
||||
$this->assertEquals([], $sut->getActions());
|
||||
$this->assertEquals(['hello' => 'world', 'actions' => []], $sut->getPayload());
|
||||
$this->assertEquals(['hello' => 'world', 'actions' => [], 'view' => 'bar'], $sut->getPayload());
|
||||
}
|
||||
|
||||
public function testSetActions()
|
||||
{
|
||||
$sut = new PageActionsEvent(new User(), ['hello' => 'world'], 'foo');
|
||||
$sut->setActions(['foo' => ['url' => 'bar']]);
|
||||
$sut = new PageActionsEvent(new User(), ['hello' => 'world'], 'foo', 'xxx');
|
||||
$sut->addAction('foo', ['url' => 'bar']);
|
||||
$this->assertEquals(['foo' => ['url' => 'bar']], $sut->getActions());
|
||||
$this->assertEquals(['hello' => 'world', 'actions' => ['foo' => ['url' => 'bar']]], $sut->getPayload());
|
||||
$this->assertEquals(['hello' => 'world', 'actions' => ['foo' => ['url' => 'bar']], 'view' => 'xxx'], $sut->getPayload());
|
||||
|
||||
$this->assertEquals(1, $sut->countActions());
|
||||
|
||||
// make sure an action with tzhe same name cannot be added
|
||||
$sut->addAction('foo', ['url' => 'bar']);
|
||||
$this->assertEquals(1, $sut->countActions());
|
||||
|
||||
$this->assertEquals(0, $sut->countActions('foo'));
|
||||
$this->assertTrue($sut->hasAction('foo'));
|
||||
$this->assertFalse($sut->hasAction('sdsd'));
|
||||
|
||||
$sut->removeAction('xxx');
|
||||
$this->assertEquals(1, $sut->countActions());
|
||||
$sut->removeAction('foo');
|
||||
$this->assertEquals(0, $sut->countActions());
|
||||
|
||||
$sut->addAction('foo', ['url' => 'bar']);
|
||||
$this->assertEquals(['foo' => ['url' => 'bar']], $sut->getActions());
|
||||
$sut->replaceAction('foo', ['url' => 'xyz']);
|
||||
$this->assertEquals(['foo' => ['url' => 'xyz']], $sut->getActions());
|
||||
}
|
||||
|
||||
public function testSubmenu()
|
||||
{
|
||||
$sut = new PageActionsEvent(new User(), ['hello' => 'world'], 'foo', 'xxx');
|
||||
$this->assertFalse($sut->hasSubmenu('test'));
|
||||
$sut->addActionToSubmenu('test', 'blub', ['url' => 'hello-world']);
|
||||
$this->assertTrue($sut->hasSubmenu('test'));
|
||||
$this->assertEquals(['test' => ['children' => ['blub' => ['url' => 'hello-world']]]], $sut->getActions());
|
||||
$sut->addActionToSubmenu('test', 'blub1', ['url' => 'hello-world']);
|
||||
$this->assertEquals(2, $sut->countActions('test'));
|
||||
}
|
||||
|
||||
public function testAddHelper()
|
||||
{
|
||||
$sut = new PageActionsEvent(new User(), ['hello' => 'world'], 'foo', 'xxx');
|
||||
|
||||
$sut->addSearchToggle();
|
||||
$sut->addDivider();
|
||||
$sut->addBack('foo1');
|
||||
$sut->addColumnToggle('foo2');
|
||||
$sut->addDelete('foo3');
|
||||
$sut->addHelp('foo4');
|
||||
$sut->addCreate('foo5', true);
|
||||
$sut->addCreate('foo6', false);
|
||||
$sut->addQuickExport('foo7');
|
||||
|
||||
$this->assertEquals(8, $sut->countActions());
|
||||
|
||||
$expected = [
|
||||
'search' => ['class' => 'search-toggle visible-xs-inline'],
|
||||
'divider0' => null,
|
||||
'back' => ['url' => 'foo1', 'translation_domain' => 'actions'],
|
||||
'visibility' => ['modal' => '#foo2'],
|
||||
'help' => ['url' => 'foo4', 'target' => '_blank'],
|
||||
'create' => ['url' => 'foo5', 'class' => 'modal-ajax-form'],
|
||||
'download' => ['url' => 'foo7', 'class' => 'toolbar-action'],
|
||||
'trash' => ['url' => 'foo3', 'class' => 'modal-ajax-form text-red'],
|
||||
];
|
||||
|
||||
$this->assertEquals($expected, $sut->getActions());
|
||||
}
|
||||
|
||||
public function testAddOthers()
|
||||
{
|
||||
$sut = new PageActionsEvent(new User(), ['hello' => 'world'], 'foo', 'xxx');
|
||||
|
||||
// make sure that modal always start with #, no matter what was given
|
||||
$sut->addColumnToggle('#fooX');
|
||||
$this->assertEquals(['visibility' => ['modal' => '#fooX']], $sut->getActions());
|
||||
// make sure that a second toggle cannot be added
|
||||
$sut->addColumnToggle('fooY');
|
||||
$this->assertEquals(['visibility' => ['modal' => '#fooX']], $sut->getActions());
|
||||
|
||||
$sut->removeAction('visibility');
|
||||
$sut->addColumnToggle('fooY');
|
||||
$this->assertEquals(['visibility' => ['modal' => '#fooY']], $sut->getActions());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\AbstractActionsSubscriber
|
||||
*/
|
||||
abstract class AbstractActionsSubscriberTest extends TestCase
|
||||
{
|
||||
protected function assertGetSubscribedEvent(string $className, string $name)
|
||||
{
|
||||
$this->assertTrue(method_exists($className, 'getSubscribedEvents'));
|
||||
$events = $className::getSubscribedEvents();
|
||||
$actionName = array_keys($events)[0];
|
||||
$config = $events[$actionName];
|
||||
$this->assertEquals('actions.' . $name, $actionName);
|
||||
$this->assertTrue(method_exists($className, $config[0]));
|
||||
$this->assertEquals(1000, $config[1]);
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ActivitiesSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ActivitiesSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ActivitiesSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ActivitiesSubscriber
|
||||
*/
|
||||
class ActivitiesSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ActivitiesSubscriber::class, 'activities');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ActivitySubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ActivitySubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ActivitySubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ActivitySubscriber
|
||||
*/
|
||||
class ActivitySubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ActivitySubscriber::class, 'activity');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/CalendarSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/CalendarSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\CalendarSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\CalendarSubscriber
|
||||
*/
|
||||
class CalendarSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(CalendarSubscriber::class, 'calendar');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/CustomerSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/CustomerSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\CustomerSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\CustomerSubscriber
|
||||
*/
|
||||
class CustomerSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(CustomerSubscriber::class, 'customer');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/CustomersSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/CustomersSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\CustomersSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\CustomersSubscriber
|
||||
*/
|
||||
class CustomersSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(CustomersSubscriber::class, 'customers');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ExportSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ExportSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ExportSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ExportSubscriber
|
||||
*/
|
||||
class ExportSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ExportSubscriber::class, 'export');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\InvoiceArchiveSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\InvoiceArchiveSubscriber
|
||||
*/
|
||||
class InvoiceArchiveSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(InvoiceArchiveSubscriber::class, 'invoice_details');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\InvoiceTemplateSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\InvoiceTemplateSubscriber
|
||||
*/
|
||||
class InvoiceTemplateSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(InvoiceTemplateSubscriber::class, 'invoice_template');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\InvoiceTemplateUploadSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\InvoiceTemplateUploadSubscriber
|
||||
*/
|
||||
class InvoiceTemplateUploadSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(InvoiceTemplateUploadSubscriber::class, 'invoice_upload');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\InvoiceTemplatesSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\InvoiceTemplatesSubscriber
|
||||
*/
|
||||
class InvoiceTemplatesSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(InvoiceTemplatesSubscriber::class, 'invoice_templates');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/InvoicesSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/InvoicesSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\InvoicesSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\InvoicesSubscriber
|
||||
*/
|
||||
class InvoicesSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(InvoicesSubscriber::class, 'invoices');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/PermissionsSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/PermissionsSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\PermissionsSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\PermissionsSubscriber
|
||||
*/
|
||||
class PermissionsSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(PermissionsSubscriber::class, 'user_permissions');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/PluginSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/PluginSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\PluginSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\PluginSubscriber
|
||||
*/
|
||||
class PluginSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(PluginSubscriber::class, 'plugin');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/PluginsSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/PluginsSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\PluginsSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\PluginsSubscriber
|
||||
*/
|
||||
class PluginsSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(PluginsSubscriber::class, 'plugins');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ProjectSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ProjectSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ProjectSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ProjectSubscriber
|
||||
*/
|
||||
class ProjectSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ProjectSubscriber::class, 'project');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ProjectsSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ProjectsSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ProjectsSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ProjectsSubscriber
|
||||
*/
|
||||
class ProjectsSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ProjectsSubscriber::class, 'projects');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/ReportingSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/ReportingSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\ReportingSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\ReportingSubscriber
|
||||
*/
|
||||
class ReportingSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(ReportingSubscriber::class, 'reporting');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\SystemConfigurationSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\SystemConfigurationSubscriber
|
||||
*/
|
||||
class SystemConfigurationSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(SystemConfigurationSubscriber::class, 'system_configuration');
|
||||
}
|
||||
}
|
||||
23
tests/EventSubscriber/Actions/TagSubscriberTest.php
Normal file
23
tests/EventSubscriber/Actions/TagSubscriberTest.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?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\Tests\EventSubscriber\Actions;
|
||||
|
||||
use App\EventSubscriber\Actions\TagSubscriber;
|
||||
|
||||
/**
|
||||
* @covers \App\EventSubscriber\Actions\TagSubscriber
|
||||
*/
|
||||
class TagSubscriberTest extends AbstractActionsSubscriberTest
|
||||
{
|
||||
public function testEventName()
|
||||
{
|
||||
$this->assertGetSubscribedEvent(TagSubscriber::class, 'tag');
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user