added team filter in timesheet search forms (#3590)

* added team filter in export and invoice search form
* added teams select to timesheet filter
* added team select to report filter
* hide user and team filter if count < 2
This commit is contained in:
Kevin Papst
2022-10-21 16:14:39 +02:00
committed by GitHub
parent 2022fa54d3
commit 14f4530de0
17 changed files with 235 additions and 17 deletions

View File

@@ -63,10 +63,6 @@ final class ReportUsersMonthController extends AbstractController
$currentUser = $this->getUser();
$dateTimeFactory = $this->getDateTimeFactory();
$query = new UserQuery();
$query->setCurrentUser($currentUser);
$allUsers = $userRepository->getUsersForQuery($query);
$values = new MonthlyUserList();
$values->setDate($dateTimeFactory->getStartOfMonth());
@@ -77,10 +73,21 @@ final class ReportUsersMonthController extends AbstractController
$form->submit($request->query->all(), false);
if ($form->isSubmitted() && !$form->isValid()) {
$values->setDate($dateTimeFactory->getStartOfMonth());
$query = new UserQuery();
$query->setCurrentUser($currentUser);
if ($form->isSubmitted()) {
if (!$form->isValid()) {
$values->setDate($dateTimeFactory->getStartOfMonth());
} else {
if ($values->getTeam() !== null) {
$query->setSearchTeams([$values->getTeam()]);
}
}
}
$allUsers = $userRepository->getUsersForQuery($query);
if ($values->getDate() === null) {
$values->setDate($dateTimeFactory->getStartOfMonth());
}

View File

@@ -63,10 +63,6 @@ final class ReportUsersWeekController extends AbstractController
$currentUser = $this->getUser();
$dateTimeFactory = $this->getDateTimeFactory();
$query = new UserQuery();
$query->setCurrentUser($currentUser);
$allUsers = $userRepository->getUsersForQuery($query);
$values = new WeeklyUserList();
$values->setDate($dateTimeFactory->getStartOfWeek());
@@ -77,10 +73,21 @@ final class ReportUsersWeekController extends AbstractController
$form->submit($request->query->all(), false);
if ($form->isSubmitted() && !$form->isValid()) {
$values->setDate($dateTimeFactory->getStartOfWeek());
$query = new UserQuery();
$query->setCurrentUser($currentUser);
if ($form->isSubmitted()) {
if (!$form->isValid()) {
$values->setDate($dateTimeFactory->getStartOfWeek());
} else {
if ($values->getTeam() !== null) {
$query->setSearchTeams([$values->getTeam()]);
}
}
}
$allUsers = $userRepository->getUsersForQuery($query);
if ($values->getDate() === null) {
$values->setDate($dateTimeFactory->getStartOfWeek());
}

View File

@@ -73,9 +73,6 @@ final class ReportUsersYearController extends AbstractController
$currentUser = $this->getUser();
$dateTimeFactory = $this->getDateTimeFactory();
$query = new UserQuery();
$query->setCurrentUser($currentUser);
$allUsers = $userRepository->getUsersForQuery($query);
$defaultDate = $dateTimeFactory->createStartOfYear();
if (null !== ($financialYear = $systemConfiguration->getFinancialYearStart())) {
@@ -92,10 +89,21 @@ final class ReportUsersYearController extends AbstractController
$form->submit($request->query->all(), false);
if ($form->isSubmitted() && !$form->isValid()) {
$values->setDate(clone $defaultDate);
$query = new UserQuery();
$query->setCurrentUser($currentUser);
if ($form->isSubmitted()) {
if (!$form->isValid()) {
$values->setDate(clone $defaultDate);
} else {
if ($values->getTeam() !== null) {
$query->setSearchTeams([$values->getTeam()]);
}
}
}
$allUsers = $userRepository->getUsersForQuery($query);
if ($values->getDate() === null) {
$values->setDate(clone $defaultDate);
}

View File

@@ -0,0 +1,88 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Form\Extension;
use App\Form\Toolbar\ExportToolbarForm;
use App\Form\Toolbar\InvoiceToolbarForm;
use App\Form\Toolbar\InvoiceToolbarSimpleForm;
use App\Form\Toolbar\TimesheetExportToolbarForm;
use App\Form\Toolbar\TimesheetToolbarForm;
use App\Form\Toolbar\UserToolbarForm;
use App\Reporting\MonthlyUserListForm;
use App\Reporting\WeeklyUserListForm;
use App\Reporting\YearlyUserListForm;
use App\User\TeamService;
use App\User\UserService;
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\FormBuilderInterface;
final class ToolbarFormExtension extends AbstractTypeExtension
{
private $userService;
private $teamService;
private $teamNames = ['team', 'teams', 'searchTeams'];
private $userNames = ['user', 'users'];
public function __construct(UserService $userService, TeamService $teamService)
{
$this->userService = $userService;
$this->teamService = $teamService;
}
public static function getExtendedTypes(): iterable
{
return [
InvoiceToolbarForm::class,
InvoiceToolbarSimpleForm::class,
ExportToolbarForm::class,
TimesheetToolbarForm::class,
TimesheetExportToolbarForm::class,
UserToolbarForm::class,
WeeklyUserListForm::class,
MonthlyUserListForm::class,
YearlyUserListForm::class,
];
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$deleteUser = false;
foreach ($this->userNames as $name) {
if ($builder->has($name) && $this->userService->countUser(true) < 2) {
$deleteUser = true;
break;
}
}
if ($deleteUser) {
foreach ($this->userNames as $name) {
if ($builder->has($name)) {
$builder->remove($name);
}
}
}
$deleteTeams = false;
foreach ($this->teamNames as $name) {
if ($builder->has($name) && !$this->teamService->hasTeams()) {
$deleteTeams = true;
break;
}
}
if ($deleteTeams) {
foreach ($this->teamNames as $name) {
if ($builder->has($name)) {
$builder->remove($name);
}
}
}
}
}

View File

@@ -31,6 +31,7 @@ class ExportToolbarForm extends AbstractToolbarForm
$this->addTimesheetStateChoice($builder);
if ($options['include_user']) {
$this->addUsersChoice($builder);
$this->addTeamsChoice($builder);
}
$this->addDateRange($builder, ['timezone' => $options['timezone']]);
$this->addCustomerMultiChoice($builder, ['start_date_param' => null, 'end_date_param' => null, 'ignore_date' => true], true);

View File

@@ -26,6 +26,7 @@ class InvoiceToolbarForm extends InvoiceToolbarSimpleForm
$this->addSearchTermInputField($builder);
if ($options['include_user']) {
$this->addUsersChoice($builder);
$this->addTeamsChoice($builder);
}
$this->addActivityMultiChoice($builder, $options, true);
$this->addTagInputField($builder);

View File

@@ -36,6 +36,7 @@ class TimesheetToolbarForm extends AbstractToolbarForm
$this->addTagInputField($builder);
if ($options['include_user']) {
$this->addUsersChoice($builder);
$this->addTeamsChoice($builder);
}
$this->addTimesheetStateChoice($builder);
$this->addBillableChoice($builder);

View File

@@ -9,11 +9,17 @@
namespace App\Reporting;
use App\Entity\Team;
abstract class AbstractUserList
{
private $date;
private $decimal = false;
private $sumType = 'duration';
/**
* @var Team|null
*/
private $team = null;
public function getDate(): ?\DateTime
{
@@ -48,4 +54,14 @@ abstract class AbstractUserList
$this->sumType = $sumType;
}
public function getTeam(): ?Team
{
return $this->team;
}
public function setTeam(?Team $team = null): void
{
$this->team = $team;
}
}

View File

@@ -11,6 +11,7 @@ namespace App\Reporting;
use App\Form\Type\MonthPickerType;
use App\Form\Type\ReportSumType;
use App\Form\Type\TeamType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
@@ -37,6 +38,11 @@ class MonthlyUserListForm extends AbstractType
'view_timezone' => $options['timezone'],
'start_date' => $options['start_date'],
]);
$builder->add('team', TeamType::class, [
'multiple' => false,
'required' => false,
'width' => false,
]);
$builder->add('sumType', ReportSumType::class);
}

View File

@@ -10,6 +10,7 @@
namespace App\Reporting;
use App\Form\Type\ReportSumType;
use App\Form\Type\TeamType;
use App\Form\Type\WeekPickerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -37,6 +38,11 @@ class WeeklyUserListForm extends AbstractType
'view_timezone' => $options['timezone'],
'start_date' => $options['start_date'],
]);
$builder->add('team', TeamType::class, [
'multiple' => false,
'required' => false,
'width' => false,
]);
$builder->add('sumType', ReportSumType::class);
}

View File

@@ -10,6 +10,7 @@
namespace App\Reporting;
use App\Form\Type\ReportSumType;
use App\Form\Type\TeamType;
use App\Form\Type\YearPickerType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
@@ -38,6 +39,11 @@ class YearlyUserListForm extends AbstractType
'start_date' => $options['start_date'],
'show_range' => true,
]);
$builder->add('team', TeamType::class, [
'multiple' => false,
'required' => false,
'width' => false,
]);
$builder->add('sumType', ReportSumType::class);
}

43
src/User/TeamService.php Normal file
View File

@@ -0,0 +1,43 @@
<?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\User;
use App\Repository\TeamRepository;
/**
* @final
*/
class TeamService
{
/**
* @var array<string, int>
*/
private $cache = [];
private $repository;
public function __construct(TeamRepository $repository)
{
$this->repository = $repository;
}
public function countTeams(): int
{
if (!\array_key_exists('count', $this->cache)) {
$this->cache['count'] = $this->repository->count([]);
}
return $this->cache['count'];
}
public function hasTeams(): bool
{
return $this->countTeams() > 0;
}
}

View File

@@ -29,6 +29,11 @@ use Symfony\Component\Validator\Validator\ValidatorInterface;
*/
class UserService
{
/**
* @var array<string, int>
*/
private $cache = [];
private $repository;
private $dispatcher;
private $validator;
@@ -44,6 +49,17 @@ class UserService
$this->encoderFactory = $encoderFactory;
}
public function countUser(?bool $enabled = null): int
{
$key = 'count' . ($enabled === null ? '_all' : ($enabled ? '_visible' : '_invisible'));
if (!\array_key_exists($key, $this->cache)) {
$this->cache[$key] = $this->repository->countUser($enabled);
}
return $this->cache[$key];
}
public function createNewUser(): User
{
$user = new User();

View File

@@ -47,6 +47,9 @@
{% if form.users is defined %}
{{ form_row(form.users) }}
{% endif %}
{% if form.teams is defined %}
{{ form_row(form.teams) }}
{% endif %}
{{ form_row(form.billable) }}
{{ form_row(form.exported) }}
{{ form_row(form.state) }}

View File

@@ -49,6 +49,9 @@
{% if form.users is defined %}
{{ form_row(form.users, {'row_attr': {'class': 'invoice_search_form_row_users'}}) }}
{% endif %}
{% if form.teams is defined %}
{{ form_row(form.teams, {'row_attr': {'class': 'invoice_search_form_row_teams'}}) }}
{% endif %}
{% if form.exported is defined %}
{{ form_row(form.exported, {'row_attr': {'class': 'invoice_search_form_row_exported'}}) }}
{% endif %}

View File

@@ -14,6 +14,9 @@
{% endblock %}
{% block box_title %}
{{ form_widget(form.date) }}
{% if form.team is defined %}
{{ form_widget(form.team) }}
{% endif %}
{% if form.sumType.vars.choices|length > 1 %}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">

View File

@@ -14,6 +14,9 @@
{% endblock %}
{% block box_title %}
{{ form_widget(form.date) }}
{% if form.team is defined %}
{{ form_widget(form.team) }}
{% endif %}
{% if form.sumType.vars.choices|length > 1 %}
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">