ROLE_ADMIN
Administrator
diff --git a/app/Resources/views/base.html.twig b/app/Resources/views/base.html.twig
index 49be2e55..dd3fa8a7 100644
--- a/app/Resources/views/base.html.twig
+++ b/app/Resources/views/base.html.twig
@@ -32,17 +32,6 @@
{% block avanzu_head %}
-
-
-
-
-
{% endblock %}
{% block avanzu_footer %}
@@ -91,5 +80,21 @@
{% block avanzu_breadcrumb %}{{ parent() }}{% endblock %}
{% block avanzu_control_sidebar %}{{ parent() }}{% endblock %}
-{% block avanzu_javascripts %}{{ parent() }}{% endblock %}
-{% block avanzu_javascripts_inline %}{{ parent() }}{% endblock %}
+
+{% block avanzu_javascripts %}
+
+
+
+
+ {% block javascript_imports %}{% endblock %}
+{% endblock %}
+
+{% block avanzu_javascripts_inline %}
+
+{% endblock %}
diff --git a/app/Resources/views/default/_toolbar_form.html.twig b/app/Resources/views/default/_toolbar_form.html.twig
new file mode 100644
index 00000000..ac43ff02
--- /dev/null
+++ b/app/Resources/views/default/_toolbar_form.html.twig
@@ -0,0 +1,9 @@
+{% import "macros/toolbar.html.twig" as toolbar %}
+
+{{ toolbar.start() }}
+ {{ form_start(form) }}
+
+ {{ form_widget(form) }}
+
+ {{ form_end(form) }}
+{{ toolbar.end() }}
diff --git a/app/Resources/views/macros/toolbar.html.twig b/app/Resources/views/macros/toolbar.html.twig
new file mode 100644
index 00000000..dc048bfd
--- /dev/null
+++ b/app/Resources/views/macros/toolbar.html.twig
@@ -0,0 +1,11 @@
+{% macro start(columns) %}
+
+
+
+{% endmacro %}
diff --git a/src/TimesheetBundle/Controller/TimesheetController.php b/src/TimesheetBundle/Controller/TimesheetController.php
index 702e2e77..5fe667a3 100644
--- a/src/TimesheetBundle/Controller/TimesheetController.php
+++ b/src/TimesheetBundle/Controller/TimesheetController.php
@@ -21,7 +21,6 @@ use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache;
use Symfony\Component\HttpFoundation\Request;
use TimesheetBundle\Form\TimesheetEditForm;
-use TimesheetBundle\Repository\TimesheetRepository;
/**
* Controller used to manage timesheet contents in the public part of the site.
@@ -33,13 +32,7 @@ use TimesheetBundle\Repository\TimesheetRepository;
*/
class TimesheetController extends AbstractController
{
- /**
- * @return TimesheetRepository
- */
- protected function getRepository()
- {
- return $this->getDoctrine()->getRepository(Timesheet::class);
- }
+ use TimesheetControllerTrait;
/**
* @Route("/", defaults={"page": 1}, name="timesheet")
@@ -47,15 +40,20 @@ class TimesheetController extends AbstractController
* @Method("GET")
* @Cache(smaxage="10")
*/
- public function indexAction($page)
+ public function indexAction($page, Request $request)
{
- $user = $this->getUser();
+ $query = $this->getQueryForRequest($request);
+ $query->setUser($this->getUser());
+ $query->setPage($page);
+
/* @var $entries Pagerfanta */
- $entries = $this->getRepository()->findLatest($user, $page);
+ $entries = $this->getRepository()->findByQuery($query);
return $this->render('TimesheetBundle:timesheet:index.html.twig', [
'entries' => $entries,
- 'page' => $page
+ 'page' => $page,
+ 'query' => $query,
+ 'toolbarForm' => $this->getToolbarForm($query)->createView(),
]);
}
diff --git a/src/TimesheetBundle/Controller/TimesheetControllerTrait.php b/src/TimesheetBundle/Controller/TimesheetControllerTrait.php
new file mode 100644
index 00000000..28c9efe6
--- /dev/null
+++ b/src/TimesheetBundle/Controller/TimesheetControllerTrait.php
@@ -0,0 +1,108 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace TimesheetBundle\Controller;
+
+use TimesheetBundle\Entity\Activity;
+use TimesheetBundle\Entity\Customer;
+use TimesheetBundle\Entity\Project;
+use TimesheetBundle\Entity\Timesheet;
+use Symfony\Component\HttpFoundation\Request;
+use TimesheetBundle\Form\TimesheetToolbarForm;
+use TimesheetBundle\Repository\TimesheetRepository;
+use TimesheetBundle\Model\Query\Timesheet as TimesheetQuery;
+
+/**
+ * Helper functions for Timesheet controller
+ *
+ * @author Kevin Papst
+ */
+trait TimesheetControllerTrait
+{
+ /**
+ * @return TimesheetRepository
+ */
+ protected function getRepository()
+ {
+ return $this->getDoctrine()->getRepository(Timesheet::class);
+ }
+
+ /**
+ * @param Request $request
+ * @return TimesheetQuery
+ */
+ protected function getQueryForRequest(Request $request)
+ {
+ $activity = $request->get('activity');
+ $activity = !empty(trim($activity)) ? trim($activity) : null;
+ $project = $request->get('project');
+ $project = !empty(trim($project)) ? trim($project) : null;
+ $customer = $request->get('customer');
+ $customer = !empty(trim($customer)) ? trim($customer) : null;
+ $state = $request->get('state');
+ $state = !empty(trim($state)) ? trim($state) : null;
+ $pageSize = (int) $request->get('pageSize');
+
+ if ($activity !== null) {
+ $repo = $this->getDoctrine()->getRepository(Activity::class);
+ $activity = $repo->getById($activity);
+ if ($activity !== null) {
+ $project = $activity->getProject();
+ if ($project !== null) {
+ $customer = $project->getCustomer();
+ }
+ } else {
+ $customer = null;
+ $project = null;
+ }
+ } elseif ($project !== null) {
+ $repo = $this->getDoctrine()->getRepository(Project::class);
+ $project = $repo->getById($project);
+ if ($project !== null) {
+ $customer = $project->getCustomer();
+ } else {
+ $customer = null;
+ }
+ } else if ($customer !== null) {
+ $repo = $this->getDoctrine()->getRepository(Customer::class);
+ $customer = $repo->getById($customer);
+ }
+
+ $query = new TimesheetQuery();
+ $query
+ ->setActivity($activity)
+ ->setProject($project)
+ ->setCustomer($customer)
+ ->setPageSize($pageSize)
+ ->setState($state);
+
+ return $query ;
+ }
+
+ /**
+ * @param TimesheetQuery $query
+ * @param string $route
+ * @return mixed
+ */
+ protected function getToolbarForm(TimesheetQuery $query, $route = 'timesheet')
+ {
+ return $this->createForm(
+ TimesheetToolbarForm::class,
+ $query,
+ [
+ 'action' => $this->generateUrl($route, [
+ 'page' => $query->getPage(),
+ ]),
+ 'method' => 'GET',
+ ]
+ );
+ }
+}
diff --git a/src/TimesheetBundle/DataFixtures/ORM/LoadFixtures.php b/src/TimesheetBundle/DataFixtures/ORM/LoadFixtures.php
index 05865645..011f2395 100644
--- a/src/TimesheetBundle/DataFixtures/ORM/LoadFixtures.php
+++ b/src/TimesheetBundle/DataFixtures/ORM/LoadFixtures.php
@@ -283,7 +283,7 @@ class LoadFixtures extends AppBundleLoadFixtures
'Customer Relations',
'Infrastructure',
'Software Upgrade',
- 'Office Managemenr',
+ 'Office Management',
];
}
diff --git a/src/TimesheetBundle/Form/CustomerEditForm.php b/src/TimesheetBundle/Form/CustomerEditForm.php
index 2959615b..49e4c2cd 100644
--- a/src/TimesheetBundle/Form/CustomerEditForm.php
+++ b/src/TimesheetBundle/Form/CustomerEditForm.php
@@ -133,7 +133,7 @@ class CustomerEditForm extends AbstractType
'data_class' => Customer::class,
'csrf_protection' => true,
'csrf_field_name' => '_token',
- 'csrf_token_id' => 'admin_activity_edit',
+ 'csrf_token_id' => 'admin_customer_edit',
]);
}
}
diff --git a/src/TimesheetBundle/Form/ProjectEditForm.php b/src/TimesheetBundle/Form/ProjectEditForm.php
index 93f43878..7d82589b 100644
--- a/src/TimesheetBundle/Form/ProjectEditForm.php
+++ b/src/TimesheetBundle/Form/ProjectEditForm.php
@@ -80,7 +80,7 @@ class ProjectEditForm extends AbstractType
'data_class' => Project::class,
'csrf_protection' => true,
'csrf_field_name' => '_token',
- 'csrf_token_id' => 'admin_activity_edit',
+ 'csrf_token_id' => 'admin_project_edit',
'currency' => Customer::DEFAULT_CURRENCY,
]);
}
diff --git a/src/TimesheetBundle/Form/TimesheetEditForm.php b/src/TimesheetBundle/Form/TimesheetEditForm.php
index bb103ea5..85d71844 100644
--- a/src/TimesheetBundle/Form/TimesheetEditForm.php
+++ b/src/TimesheetBundle/Form/TimesheetEditForm.php
@@ -19,6 +19,7 @@ use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use TimesheetBundle\Entity\Customer;
use TimesheetBundle\Entity\Timesheet;
+use TimesheetBundle\Form\Type\ActivityGroupedWithCustomerNameType;
/**
* Defines the form used to manipulate Timesheet entries.
@@ -47,18 +48,15 @@ class TimesheetEditForm extends AbstractType
])
// integer
/*
- ->add('duration', RangeType::class, [
- 'label' => 'label.duration',
- ])
// User
->add('user', UserType::class, [
'label' => 'label.user',
])
+ */
// Activity
- ->add('activity', ActivityType::class, [
+ ->add('activity', ActivityGroupedWithCustomerNameType::class, [
'label' => 'label.activity',
])
- */
// customer
->add('description', TextareaType::class, [
'label' => 'label.description',
@@ -81,7 +79,7 @@ class TimesheetEditForm extends AbstractType
'data_class' => Timesheet::class,
'csrf_protection' => true,
'csrf_field_name' => '_token',
- 'csrf_token_id' => 'admin_timsheet_edit',
+ 'csrf_token_id' => 'timesheet_edit',
'currency' => Customer::DEFAULT_CURRENCY,
]);
}
diff --git a/src/TimesheetBundle/Form/TimesheetToolbarForm.php b/src/TimesheetBundle/Form/TimesheetToolbarForm.php
new file mode 100644
index 00000000..c7b93965
--- /dev/null
+++ b/src/TimesheetBundle/Form/TimesheetToolbarForm.php
@@ -0,0 +1,131 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace TimesheetBundle\Form;
+
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
+use Symfony\Component\Form\FormBuilderInterface;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use TimesheetBundle\Form\Type\ActivityType;
+use TimesheetBundle\Form\Type\CustomerType;
+use TimesheetBundle\Form\Type\ProjectType;
+use TimesheetBundle\Model\Query\Timesheet as TimesheetQuery;
+
+/**
+ * Defines the form used for filtering the timesheet.
+ *
+ * @author Kevin Papst
+ */
+class TimesheetToolbarForm extends AbstractType
+{
+ /**
+ * Dirty hack to enable easy handling of GET form in controller and javascript.
+ *Cleans up the name of all form elents (and unfortunately of the form itself).
+ *
+ * @return null|string
+ */
+ public function getBlockPrefix()
+ {
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ /** @var TimesheetQuery $query */
+ $query = $options['data'];
+
+ $builder
+ ->add('pageSize', ChoiceType::class, [
+ 'label' => 'label.pageSize',
+ 'choices' => [10 => 10, 25 => 25, 50 => 50, 75 => 75, 100 => 100],
+ 'required' => false,
+ ])
+ ->add('state', ChoiceType::class, [
+ 'label' => 'label.entryState',
+ 'choices' => [
+ 'entryState.all' => TimesheetQuery::STATE_ALL,
+ 'entryState.running' => TimesheetQuery::STATE_RUNNING,
+ 'entryState.stopped' => TimesheetQuery::STATE_STOPPED
+ ],
+ ])
+ ->add('customer', CustomerType::class, [
+ 'label' => 'label.customer',
+ 'required' => false,
+ ])
+ ;
+
+ $this->addProjectChoice($builder, $query);
+ $this->addActivityChoice($builder, $query);
+ }
+
+ /**
+ * @param FormBuilderInterface $builder
+ * @param TimesheetQuery $query
+ */
+ protected function addProjectChoice(FormBuilderInterface $builder, TimesheetQuery $query)
+ {
+ if ($query->getCustomer() === null) {
+ return;
+ }
+
+ $choices = [];
+ foreach ($query->getCustomer()->getProjects() as $project) {
+ $choices[] = $project;
+ //$choices[$project->getName()] = $project->getId();
+ }
+
+ $builder
+ ->add('project', ProjectType::class, [
+ 'label' => 'label.project',
+ 'required' => false,
+ 'choices' => $choices,
+ ]);
+ }
+
+ /**
+ * @param FormBuilderInterface $builder
+ * @param TimesheetQuery $query
+ */
+ protected function addActivityChoice(FormBuilderInterface $builder, TimesheetQuery $query)
+ {
+ if ($query->getProject() === null) {
+ return;
+ }
+
+ $choices = [];
+ foreach ($query->getProject()->getActivities() as $activity) {
+ $choices[] = $activity;
+ //$choices[$activity->getName()] = $activity->getId();
+ }
+
+ $builder
+ ->add('activity', ActivityType::class, [
+ 'label' => 'label.activity',
+ 'required' => false,
+ 'choices' => $choices,
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'data_class' => TimesheetQuery::class,
+ 'csrf_protection' => false,
+ ]);
+ }
+}
diff --git a/src/TimesheetBundle/Form/Type/ActivityGroupedWithCustomerNameType.php b/src/TimesheetBundle/Form/Type/ActivityGroupedWithCustomerNameType.php
new file mode 100644
index 00000000..5d3ea4d6
--- /dev/null
+++ b/src/TimesheetBundle/Form/Type/ActivityGroupedWithCustomerNameType.php
@@ -0,0 +1,34 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace TimesheetBundle\Form\Type;
+
+use TimesheetBundle\Entity\Activity;
+
+/**
+ * Custom form field type to select an activity which are grouped by their Projects, preceeded by their customer names.
+ *
+ * @author Kevin Papst
+ */
+class ActivityGroupedWithCustomerNameType extends ActivityType
+{
+
+ /**
+ * @param Activity $activity
+ * @param $key
+ * @param $index
+ * @return string
+ */
+ public function groupBy(Activity $activity, $key, $index)
+ {
+ return $activity->getProject()->getCustomer()->getName() . ': ' . $activity->getProject()->getName();
+ }
+}
diff --git a/src/TimesheetBundle/Form/Type/ActivityType.php b/src/TimesheetBundle/Form/Type/ActivityType.php
new file mode 100644
index 00000000..45996bf3
--- /dev/null
+++ b/src/TimesheetBundle/Form/Type/ActivityType.php
@@ -0,0 +1,58 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace TimesheetBundle\Form\Type;
+
+use Symfony\Bridge\Doctrine\Form\Type\EntityType;
+use Symfony\Component\Form\AbstractType;
+use Symfony\Component\OptionsResolver\OptionsResolver;
+use TimesheetBundle\Entity\Activity;
+
+/**
+ * Custom form field type to select an activity.
+ *
+ * @author Kevin Papst
+ */
+class ActivityType extends AbstractType
+{
+
+ /**
+ * @param Activity $activity
+ * @param $key
+ * @param $index
+ * @return string
+ */
+ public function groupBy(Activity $activity, $key, $index)
+ {
+ return $activity->getProject()->getName();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'class' => 'TimesheetBundle:Activity',
+ 'choice_label' => 'name',
+ 'choice_value' => 'id',
+ 'group_by' => array($this, 'groupBy'),
+ ]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getParent()
+ {
+ return EntityType::class;
+ }
+}
diff --git a/src/TimesheetBundle/Form/Type/ProjectType.php b/src/TimesheetBundle/Form/Type/ProjectType.php
index 6f041205..67a1eabb 100644
--- a/src/TimesheetBundle/Form/Type/ProjectType.php
+++ b/src/TimesheetBundle/Form/Type/ProjectType.php
@@ -11,9 +11,10 @@
namespace TimesheetBundle\Form\Type;
-use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;
+use TimesheetBundle\Entity\Project;
/**
* Custom form field type to select a project.
@@ -30,14 +31,10 @@ class ProjectType extends AbstractType
{
$resolver->setDefaults([
'class' => 'TimesheetBundle:Project',
- 'choice_label' => function ($project) {
- /* @var $project Project */
- return
- //'[' . $project->getId() . '] ' .
- $project->getName() .
- ' (' .
- $project->getCustomer()->getName() .
- ')';
+ 'choice_label' => 'name',
+ 'choice_value' => 'id',
+ 'group_by' => function(Project $project, $key, $index) {
+ return $project->getCustomer()->getName();
},
]);
}
@@ -47,6 +44,6 @@ class ProjectType extends AbstractType
*/
public function getParent()
{
- return EntityType::class;
+ return ChoiceType::class;
}
}
diff --git a/src/TimesheetBundle/Model/Query/Timesheet.php b/src/TimesheetBundle/Model/Query/Timesheet.php
new file mode 100644
index 00000000..c58a7569
--- /dev/null
+++ b/src/TimesheetBundle/Model/Query/Timesheet.php
@@ -0,0 +1,201 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace TimesheetBundle\Model\Query;
+
+use AppBundle\Entity\User;
+use TimesheetBundle\Entity\Activity;
+use TimesheetBundle\Entity\Customer;
+use TimesheetBundle\Entity\Project;
+
+/**
+ * Can be used for advanced timesheet repository queries.
+ *
+ * @author Kevin Papst
+ */
+class Timesheet
+{
+
+ const DEFAULT_PAGESIZE = 25;
+ const DEFAULT_PAGE = 1;
+
+ const STATE_ALL = 0;
+ const STATE_RUNNING = 1;
+ const STATE_STOPPED = 2;
+
+ /**
+ * @var User
+ */
+ protected $user;
+ /**
+ * @var Activity
+ */
+ protected $activity;
+ /**
+ * @var Project
+ */
+ protected $project;
+ /**
+ * @var Customer
+ */
+ protected $customer;
+ /**
+ * @var int
+ */
+ protected $page = self::DEFAULT_PAGE;
+ /**
+ * @var int
+ */
+ protected $pageSize = self::DEFAULT_PAGESIZE;
+ /**
+ * @var int
+ */
+ protected $state = self::STATE_ALL;
+
+ /**
+ * @return User
+ */
+ public function getUser()
+ {
+ return $this->user;
+ }
+
+ /**
+ * @param User $user
+ * @return Timesheet
+ */
+ public function setUser(User $user = null)
+ {
+ $this->user = $user;
+ return $this;
+ }
+
+ /**
+ * Activity overwrites: setProject() and setCustomer()
+ *
+ * @return Activity
+ */
+ public function getActivity()
+ {
+ return $this->activity;
+ }
+
+ /**
+ * @param Activity $activity
+ * @return Timesheet
+ */
+ public function setActivity(Activity $activity = null)
+ {
+ $this->activity = $activity;
+ return $this;
+ }
+
+ /**
+ * @return Project
+ */
+ public function getProject()
+ {
+ return $this->project;
+ }
+
+ /**
+ * Project overwrites: setCustomer()
+ * Is overwritten by: setActivity()
+ *
+ * @param Project $project
+ * @return Timesheet
+ */
+ public function setProject(Project $project = null)
+ {
+ $this->project = $project;
+ return $this;
+ }
+
+ /**
+ * @return Customer
+ */
+ public function getCustomer()
+ {
+ return $this->customer;
+ }
+
+ /**
+ * Project overwrites: none
+ * Is overwritten by: setActivity() and setProject()
+ *
+ * @param Customer $customer
+ * @return Timesheet
+ */
+ public function setCustomer(Customer $customer = null)
+ {
+ $this->customer = $customer;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPage()
+ {
+ return $this->page;
+ }
+
+ /**
+ * @param int $page
+ * @return Timesheet
+ */
+ public function setPage($page)
+ {
+ $this->page = $page;
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPageSize()
+ {
+ return $this->pageSize;
+ }
+
+ /**
+ * @param int $pageSize
+ * @return Timesheet
+ */
+ public function setPageSize($pageSize)
+ {
+ if (!empty($pageSize) && (int) $pageSize > 0) {
+ $this->pageSize = (int) $pageSize;
+ }
+ return $this;
+ }
+
+ /**
+ * @return int
+ */
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ /**
+ * @param int $state
+ * @return Timesheet
+ */
+ public function setState($state)
+ {
+ if (in_array($state, [self::STATE_ALL, self::STATE_RUNNING, self::STATE_STOPPED])) {
+ $this->state = $state;
+ }
+ return $this;
+ }
+
+}
diff --git a/src/TimesheetBundle/Repository/TimesheetRepository.php b/src/TimesheetBundle/Repository/TimesheetRepository.php
index acac527c..8e74a2a9 100644
--- a/src/TimesheetBundle/Repository/TimesheetRepository.php
+++ b/src/TimesheetBundle/Repository/TimesheetRepository.php
@@ -22,6 +22,7 @@ use Pagerfanta\Pagerfanta;
use TimesheetBundle\Model\Statistic\Month;
use TimesheetBundle\Model\Statistic\Year;
use TimesheetBundle\Model\TimesheetGlobalStatistic;
+use TimesheetBundle\Model\Query\Timesheet as TimesheetQuery;
use TimesheetBundle\Model\TimesheetStatistic;
use DateTime;
@@ -291,6 +292,42 @@ class TimesheetRepository extends EntityRepository
return $qb->getQuery();
}
+ public function findByQuery(TimesheetQuery $query)
+ {
+ $qb = $this->getEntityManager()->createQueryBuilder();
+
+ $qb->select('t', 'a')
+ ->from('TimesheetBundle:Timesheet', 't')
+ ->join('t.activity', 'a')
+ ->orderBy('t.begin', 'DESC');
+
+ if ($query->getUser() !== null) {
+ $qb->andWhere('t.user = :user')
+ ->setParameter('user', $query->getUser());
+ }
+
+ if ($query->getState() == TimesheetQuery::STATE_RUNNING) {
+ $qb->andWhere($qb->expr()->isNull('t.end'));
+ } elseif ($query->getState() == TimesheetQuery::STATE_STOPPED) {
+ $qb->andWhere($qb->expr()->isNotNull('t.end'));
+ }
+
+ if ($query->getActivity() !== null) {
+ $qb->andWhere('t.activity = :activity')
+ ->setParameter('activity', $query->getActivity());
+ } elseif ($query->getProject() !== null) {
+ $qb->andWhere('a.project = :project')
+ ->setParameter('project', $query->getProject());
+ } elseif ($query->getCustomer() !== null) {
+ $qb->join('a.project', 'p')
+ ->join('p.customer', 'c')
+ ->andWhere('p.customer = :customer')
+ ->setParameter('customer', $query->getCustomer());
+ }
+
+ return $this->getPager($qb->getQuery(), $query->getPage(), $query->getPageSize());
+ }
+
/**
* @param User $user
* @param int $page
@@ -314,12 +351,13 @@ class TimesheetRepository extends EntityRepository
/**
* @param Query $query
* @param int $page
+ * @param int $maxPerPage
* @return Pagerfanta
*/
- protected function getPager(Query $query, $page = 1)
+ protected function getPager(Query $query, $page = 1, $maxPerPage = 25)
{
$paginator = new Pagerfanta(new DoctrineORMAdapter($query, false));
- $paginator->setMaxPerPage(25);
+ $paginator->setMaxPerPage($maxPerPage);
$paginator->setCurrentPage($page);
return $paginator;
diff --git a/src/TimesheetBundle/Resources/translations/messages.de.xliff b/src/TimesheetBundle/Resources/translations/messages.de.xliff
new file mode 100644
index 00000000..35606a5a
--- /dev/null
+++ b/src/TimesheetBundle/Resources/translations/messages.de.xliff
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+ label.pageSize
+ Anzahl Einträge
+
+
+ timesheet.toolbar.submit
+ Einträge filtern
+
+
+ label.entryState
+ Zeiten
+
+
+ entryState.all
+ Alle
+
+
+ entryState.running
+ Laufende
+
+
+ entryState.stopped
+ Beendete
+
+
+ 0
+ 0
+
+
+ 10
+ 10
+
+
+ 25
+ 25
+
+
+ 50
+ 50
+
+
+ 75
+ 75
+
+
+ 100
+ 100
+
+
+
+
+
diff --git a/src/TimesheetBundle/Resources/views/timesheet/index.html.twig b/src/TimesheetBundle/Resources/views/timesheet/index.html.twig
index 87523b8e..2a914bcf 100644
--- a/src/TimesheetBundle/Resources/views/timesheet/index.html.twig
+++ b/src/TimesheetBundle/Resources/views/timesheet/index.html.twig
@@ -4,8 +4,13 @@
{% block page_title %}{{ 'timesheet.title'|trans }}{% endblock %}
{% block page_subtitle %}{{ 'timesheet.subtitle'|trans }}{% endblock %}
+{% block javascript_imports %}{% endblock %}
{% block main %}
+ {% if toolbarForm %}
+ {{ include('default/_toolbar_form.html.twig', {'form': toolbarForm}) }}
+ {% endif %}
+
{% if entries.count > 0 %}
{{ datatables.data_table_header({
'label.date': '',
diff --git a/web/css/kimai.css b/web/css/kimai.css
index 2bc92e17..a323c19e 100644
--- a/web/css/kimai.css
+++ b/web/css/kimai.css
@@ -31,6 +31,17 @@ li.open .ticktac i.running{
}
*/
+/* ================================ TOOLBAR ================================ */
+
+.toolbar form input,
+.toolbar form select {
+ display: inline-block;
+ width: inherit;
+}
+
+.toolbar form .form-group {
+ display: inline;
+}
/* ================================ SIDEBAR ================================ */
diff --git a/web/js/timesheet.js b/web/js/timesheet.js
new file mode 100644
index 00000000..549bc3a6
--- /dev/null
+++ b/web/js/timesheet.js
@@ -0,0 +1,24 @@
+$(document).ready(function () {
+
+ $('.toolbar form select').change(function (event) {
+ switch (event.target.id) {
+ case 'customer':
+ if ($(this).val() === '') {
+ $('.toolbar form select#project').parent().remove();
+ } else {
+ $('.toolbar form select#project').val('');
+ }
+ $('.toolbar form select#activity').parent().remove();
+ break;
+ case 'project':
+ if ($(this).val() === '') {
+ $('.toolbar form select#activity').parent().remove();
+ } else {
+ $('.toolbar form select#activity').val('');
+ }
+ break;
+ }
+ $('.toolbar form').submit();
+ });
+
+});