From 9e2fccb105281dcf753952896f1dcc67fa288b61 Mon Sep 17 00:00:00 2001 From: Kevin Papst Date: Thu, 30 Jan 2020 21:51:27 +0100 Subject: [PATCH] added pagination to working time widget (#1418) --- config/packages/kimai.yaml | 5 +- src/Controller/WidgetController.php | 35 +++++ src/Repository/TimesheetRepository.php | 8 +- src/Widget/Type/DailyWorkingTimeChart.php | 13 +- src/Widget/Type/PaginatedWorkingTimeChart.php | 101 ++++++++++++++ .../paginatedworkingtimechart.html.twig | 1 + .../widget-dailyworkingtimechart.html.twig | 131 ++++++++++-------- ...widget-paginatedworkingtimechart.html.twig | 74 ++++++++++ .../Widget/Type/DailyWorkingTimeChartTest.php | 6 +- 9 files changed, 302 insertions(+), 72 deletions(-) create mode 100644 src/Controller/WidgetController.php create mode 100644 src/Widget/Type/PaginatedWorkingTimeChart.php create mode 100644 templates/widget/paginatedworkingtimechart.html.twig create mode 100644 templates/widget/widget-paginatedworkingtimechart.html.twig diff --git a/config/packages/kimai.yaml b/config/packages/kimai.yaml index 64c0f93d..4e873ada 100644 --- a/config/packages/kimai.yaml +++ b/config/packages/kimai.yaml @@ -179,11 +179,10 @@ kimai: # -------------------------------------------------------------------------------- dashboard: user_duration: - title: stats.yourWorkingHours + title: ~ order: 10 permission: view_own_timesheet - type: '\App\Widget\Type\CompoundChart' - widgets: [DailyWorkingTimeChart, userDurationToday, userDurationWeek, userDurationMonth, userDurationYear] + widgets: [PaginatedWorkingTimeChart] user_teams: title: ~ order: 15 diff --git a/src/Controller/WidgetController.php b/src/Controller/WidgetController.php new file mode 100644 index 00000000..dcd26807 --- /dev/null +++ b/src/Controller/WidgetController.php @@ -0,0 +1,35 @@ +render('widget/paginatedworkingtimechart.html.twig', [ + 'user' => $this->getUser(), + 'year' => $year, + 'week' => $week, + ]); + } +} diff --git a/src/Repository/TimesheetRepository.php b/src/Repository/TimesheetRepository.php index b43f51ad..80e8f275 100644 --- a/src/Repository/TimesheetRepository.php +++ b/src/Repository/TimesheetRepository.php @@ -431,20 +431,20 @@ class TimesheetRepository extends EntityRepository */ public function getDailyStats(User $user, DateTime $begin, DateTime $end): array { - $results = $this->getDailyData($begin, $end, $user); - /** @var Day[] $days */ $days = []; // prefill the array $tmp = clone $end; $until = (int) $begin->format('Ymd'); - while ((int) $tmp->format('Ymd') > $until) { - $tmp->modify('-1 day'); + while ((int) $tmp->format('Ymd') >= $until) { $last = clone $tmp; $days[$last->format('Ymd')] = new Day($last, 0, 0.00); + $tmp->modify('-1 day'); } + $results = $this->getDailyData($begin, $end, $user); + foreach ($results as $statRow) { $dateTime = new DateTime(); $dateTime->setDate($statRow['year'], $statRow['month'], $statRow['day']); diff --git a/src/Widget/Type/DailyWorkingTimeChart.php b/src/Widget/Type/DailyWorkingTimeChart.php index 169902e0..f90ed3bf 100644 --- a/src/Widget/Type/DailyWorkingTimeChart.php +++ b/src/Widget/Type/DailyWorkingTimeChart.php @@ -63,8 +63,17 @@ class DailyWorkingTimeChart extends SimpleWidget $options = $this->getOptions($options); $user = $options['user']; - $begin = new DateTime($options['begin'], $this->dateTimeFactory->getTimezone()); - $end = new DateTime($options['end'], $this->dateTimeFactory->getTimezone()); + if ($options['begin'] instanceof DateTime) { + $begin = $options['begin']; + } else { + $begin = new DateTime($options['begin'], $this->dateTimeFactory->getTimezone()); + } + + if ($options['end'] instanceof DateTime) { + $end = $options['end']; + } else { + $end = new DateTime($options['end'], $this->dateTimeFactory->getTimezone()); + } return $this->repository->getDailyStats($user, $begin, $end); } diff --git a/src/Widget/Type/PaginatedWorkingTimeChart.php b/src/Widget/Type/PaginatedWorkingTimeChart.php new file mode 100644 index 00000000..1d536026 --- /dev/null +++ b/src/Widget/Type/PaginatedWorkingTimeChart.php @@ -0,0 +1,101 @@ +repository = $repository; + $this->dateTimeFactory = $dateTime; + $this->setId('PaginatedWorkingTimeChart'); + $this->setTitle('stats.yourWorkingHours'); + + $this->setOptions([ + 'year' => (new DateTime('now', $this->dateTimeFactory->getTimezone()))->format('Y'), + 'week' => (new DateTime('now', $this->dateTimeFactory->getTimezone()))->format('W'), + 'user' => $user->getUser(), + 'type' => 'bar', + ]); + } + + public function getOptions(array $options = []): array + { + $options = parent::getOptions($options); + + if (!in_array($options['type'], ['bar', 'line'])) { + $options['type'] = 'bar'; + } + + return $options; + } + + private function getDate($year, $week, $day, $hour, $minute, $second) + { + $now = new DateTime('now', $this->dateTimeFactory->getTimezone()); + $now->setISODate($year, $week, $day); + $now->setTime($hour, $minute, $second); + + return $now; + } + + public function getData(array $options = []) + { + $options = $this->getOptions($options); + $user = $options['user']; + + $weekBegin = $this->getDate($options['year'], $options['week'], 1, 0, 0, 0); + $weekEnd = $this->getDate($options['year'], $options['week'], 7, 23, 59, 59); + + return [ + 'begin' => clone $weekBegin, + 'end' => clone $weekEnd, + 'stats' => $this->repository->getDailyStats($user, $weekBegin, $weekEnd), + 'day' => $this->repository->getStatistic( + 'duration', + new DateTime('00:00:00', $this->dateTimeFactory->getTimezone()), + new DateTime('23:59:59', $this->dateTimeFactory->getTimezone()), + $user + ), + 'week' => $this->repository->getStatistic( + 'duration', + $weekBegin, + $weekEnd, + $user + ), + 'month' => $this->repository->getStatistic( + 'duration', + (clone $weekBegin)->setDate($weekBegin->format('Y'), $weekBegin->format('n'), 1)->setTime(0, 0, 0), + (clone $weekBegin)->setDate($weekBegin->format('Y'), $weekBegin->format('n'), $weekBegin->format('t'))->setTime(23, 59, 59), + $user + ), + 'year' => $this->repository->getStatistic( + 'duration', + new DateTime(sprintf('01 january %s 00:00:00', $options['year']), $this->dateTimeFactory->getTimezone()), + new DateTime(sprintf('31 december %s 23:59:59', $options['year']), $this->dateTimeFactory->getTimezone()), + $user + ), + ]; + } +} diff --git a/templates/widget/paginatedworkingtimechart.html.twig b/templates/widget/paginatedworkingtimechart.html.twig new file mode 100644 index 00000000..83656ec3 --- /dev/null +++ b/templates/widget/paginatedworkingtimechart.html.twig @@ -0,0 +1 @@ +{{ render_widget('PaginatedWorkingTimeChart', {'year': year, 'week': week}) }} diff --git a/templates/widget/widget-dailyworkingtimechart.html.twig b/templates/widget/widget-dailyworkingtimechart.html.twig index 908ca541..a2efaa16 100644 --- a/templates/widget/widget-dailyworkingtimechart.html.twig +++ b/templates/widget/widget-dailyworkingtimechart.html.twig @@ -12,76 +12,85 @@ {% endif %} {% endif %} -{{ encore_entry_link_tags('chart') }} -{{ encore_entry_script_tags('chart') }} -
diff --git a/templates/widget/widget-paginatedworkingtimechart.html.twig b/templates/widget/widget-paginatedworkingtimechart.html.twig new file mode 100644 index 00000000..2bd38d54 --- /dev/null +++ b/templates/widget/widget-paginatedworkingtimechart.html.twig @@ -0,0 +1,74 @@ +
+
+ {% embed '@AdminLTE/Widgets/box-widget.html.twig' %} + {% block box_title %} + {% if not title is empty %}{{ title|trans }}{% endif %} + {% endblock %} + {% block box_attributes %} + id="PaginatedWorkingTimeChart" data-href="#" data-reload="" + {% endblock %} + {% block box_tools %} +
    + {% set prevYear = options.year %} + {% set prevWeek = options.week %} + {% set nextYear = options.year %} + {% set nextWeek = options.week %} + {% if prevWeek == 1 %} + {% set prevYear = prevYear - 1 %} + {% set prevWeek = 52 %} + {% else %} + {% set prevWeek = prevWeek - 1 %} + {% endif %} + {% if nextWeek == 52 %} + {% set nextYear = nextYear + 1 %} + {% set nextWeek = 1 %} + {% else %} + {% set nextWeek = nextWeek + 1 %} + {% endif %} + + +
+ {% endblock %} + {% block box_body %} +
+
+ {{ render_widget('DailyWorkingTimeChart', options|merge({'begin': data.begin, 'end': data.end})) }} +
+
+ {% endblock %} + {% block box_footer %} +
+
+
+
{{ data.day|duration }}
+ {{ 'stats.durationToday'|trans }} +
+
+
+
+
{{ data.week|duration }}
+ {{ 'stats.durationWeek'|trans }} +
+
+
+
+
{{ data.month|duration }}
+ {{ 'stats.durationMonth'|trans }} +
+
+
+
+
{{ data.year|duration }}
+ {{ 'stats.durationYear'|trans }} +
+
+
+ {% endblock %} + {% endembed %} +
+
+ diff --git a/tests/Widget/Type/DailyWorkingTimeChartTest.php b/tests/Widget/Type/DailyWorkingTimeChartTest.php index f4c0b743..fda5b2dd 100644 --- a/tests/Widget/Type/DailyWorkingTimeChartTest.php +++ b/tests/Widget/Type/DailyWorkingTimeChartTest.php @@ -101,9 +101,11 @@ class DailyWorkingTimeChartTest extends TestCase public function testGetData() { $repository = $this->getMockBuilder(TimesheetRepository::class)->disableOriginalConstructor()->onlyMethods(['getDailyData'])->getMock(); - $repository->expects($this->once())->method('getDailyData')->willReturnCallback(function ($user, $begin, $end) { + $repository->expects($this->once())->method('getDailyData')->willReturnCallback(function ($begin, $end, $user) { + $today = (new \DateTime()); + return [ - ['year' => '2019', 'month' => '1', 'day' => 1, 'rate' => 13.75, 'duration' => 1234] + ['year' => $today->format('Y'), 'month' => $today->format('n'), 'day' => $today->format('j'), 'rate' => 13.75, 'duration' => 1234] ]; });