added config for initial calendar view (#363)
This commit is contained in:
@@ -18,7 +18,7 @@ use Symfony\Component\HttpKernel\KernelEvents;
|
|||||||
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class ThemeOptionsSubscriber
|
* Allows dynamic injection of theme related options.
|
||||||
*/
|
*/
|
||||||
class ThemeOptionsSubscriber implements EventSubscriberInterface
|
class ThemeOptionsSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
@@ -33,7 +33,6 @@ class ThemeOptionsSubscriber implements EventSubscriberInterface
|
|||||||
protected $helper;
|
protected $helper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThemeOptionsSubscriber constructor.
|
|
||||||
* @param TokenStorageInterface $storage
|
* @param TokenStorageInterface $storage
|
||||||
* @param ContextHelper $helper
|
* @param ContextHelper $helper
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace App\EventSubscriber;
|
|||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
use App\Entity\UserPreference;
|
use App\Entity\UserPreference;
|
||||||
use App\Event\UserPreferenceEvent;
|
use App\Event\UserPreferenceEvent;
|
||||||
|
use App\Form\Type\CalendarViewType;
|
||||||
use App\Form\Type\SkinType;
|
use App\Form\Type\SkinType;
|
||||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
@@ -95,6 +96,11 @@ class UserPreferenceSubscriber implements EventSubscriberInterface
|
|||||||
->setValue(true)
|
->setValue(true)
|
||||||
->setType(CheckboxType::class),
|
->setType(CheckboxType::class),
|
||||||
|
|
||||||
|
(new UserPreference())
|
||||||
|
->setName('calendar.initial_view')
|
||||||
|
->setValue(CalendarViewType::DEFAULT_VIEW)
|
||||||
|
->setType(CalendarViewType::class),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
(new UserPreference())
|
(new UserPreference())
|
||||||
->setName('language')
|
->setName('language')
|
||||||
|
|||||||
52
src/Form/Type/CalendarViewType.php
Normal file
52
src/Form/Type/CalendarViewType.php
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<?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\Type;
|
||||||
|
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom form field type to select a calendar view.
|
||||||
|
*/
|
||||||
|
class CalendarViewType extends AbstractType
|
||||||
|
{
|
||||||
|
public const DEFAULT_VIEW = 'month';
|
||||||
|
|
||||||
|
public const ALLOWED_VIEWS = [
|
||||||
|
'month',
|
||||||
|
'agendaWeek',
|
||||||
|
'agendaDay',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function configureOptions(OptionsResolver $resolver)
|
||||||
|
{
|
||||||
|
$choices = [];
|
||||||
|
foreach (self::ALLOWED_VIEWS as $name) {
|
||||||
|
$choices[$name] = $name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'required' => true,
|
||||||
|
'choices' => $choices,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getParent()
|
||||||
|
{
|
||||||
|
return ChoiceType::class;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,7 @@
|
|||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('#calendar').fullCalendar({
|
$('#calendar').fullCalendar({
|
||||||
|
defaultView: '{{ app.user.getPreferenceValue('calendar.initial_view') }}',
|
||||||
{% if not google.apiKey is null %}
|
{% if not google.apiKey is null %}
|
||||||
googleCalendarApiKey: '{{ google.apiKey }}',
|
googleCalendarApiKey: '{{ google.apiKey }}',
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -84,7 +85,7 @@
|
|||||||
'</div>'
|
'</div>'
|
||||||
,
|
,
|
||||||
trigger: 'hover',
|
trigger: 'hover',
|
||||||
placement: 'top',
|
placement: 'auto',
|
||||||
container: 'body',
|
container: 'body',
|
||||||
html: true
|
html: true
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace App\Tests\Controller;
|
|||||||
|
|
||||||
use App\DataFixtures\UserFixtures;
|
use App\DataFixtures\UserFixtures;
|
||||||
use App\Entity\User;
|
use App\Entity\User;
|
||||||
|
use App\Entity\UserPreference;
|
||||||
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,4 +207,54 @@ class ProfileControllerTest extends ControllerBaseTest
|
|||||||
|
|
||||||
$this->assertEquals(['ROLE_TEAMLEAD', 'ROLE_SUPER_ADMIN', 'ROLE_USER'], $user->getRoles());
|
$this->assertEquals(['ROLE_TEAMLEAD', 'ROLE_SUPER_ADMIN', 'ROLE_USER'], $user->getRoles());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testPreferencesAction()
|
||||||
|
{
|
||||||
|
$client = $this->getClientForAuthenticatedUser(User::ROLE_USER);
|
||||||
|
$this->request($client, '/profile/' . UserFixtures::USERNAME_USER . '/prefs');
|
||||||
|
|
||||||
|
/** @var User $user */
|
||||||
|
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||||
|
$user = $this->getUserByRole($em, User::ROLE_USER);
|
||||||
|
|
||||||
|
$this->assertEquals(82, $user->getPreferenceValue(UserPreference::HOURLY_RATE));
|
||||||
|
$this->assertEquals('green', $user->getPreferenceValue(UserPreference::SKIN));
|
||||||
|
$this->assertEquals(true, $user->getPreferenceValue('theme.fixed_layout'));
|
||||||
|
$this->assertEquals(false, $user->getPreferenceValue('theme.boxed_layout'));
|
||||||
|
$this->assertEquals(false, $user->getPreferenceValue('theme.collapsed_sidebar'));
|
||||||
|
$this->assertEquals(true, $user->getPreferenceValue('theme.mini_sidebar'));
|
||||||
|
$this->assertEquals('month', $user->getPreferenceValue('calendar.initial_view'));
|
||||||
|
|
||||||
|
$form = $client->getCrawler()->filter('form[name=user_preferences_form]')->form();
|
||||||
|
$client->submit($form, [
|
||||||
|
'user_preferences_form' => [
|
||||||
|
'preferences' => [
|
||||||
|
['name' => UserPreference::HOURLY_RATE, 'value' => 37],
|
||||||
|
['name' => UserPreference::SKIN, 'value' => 'blue'],
|
||||||
|
['name' => 'theme.fixed_layout', 'value' => false],
|
||||||
|
['name' => 'theme.boxed_layout', 'value' => true],
|
||||||
|
['name' => 'theme.collapsed_sidebar', 'value' => true],
|
||||||
|
['name' => 'theme.mini_sidebar', 'value' => false],
|
||||||
|
['name' => 'calendar.initial_view', 'value' => 'agendaDay'],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertIsRedirect($client, $this->createUrl('/profile/' . urlencode(UserFixtures::USERNAME_USER) . '/prefs'));
|
||||||
|
$client->followRedirect();
|
||||||
|
$this->assertTrue($client->getResponse()->isSuccessful());
|
||||||
|
|
||||||
|
$this->assertHasFlashSuccess($client);
|
||||||
|
|
||||||
|
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
|
||||||
|
$user = $this->getUserByRole($em, User::ROLE_USER);
|
||||||
|
|
||||||
|
$this->assertEquals(37, $user->getPreferenceValue(UserPreference::HOURLY_RATE));
|
||||||
|
$this->assertEquals('blue', $user->getPreferenceValue(UserPreference::SKIN));
|
||||||
|
$this->assertEquals(false, $user->getPreferenceValue('theme.fixed_layout'));
|
||||||
|
$this->assertEquals(true, $user->getPreferenceValue('theme.boxed_layout'));
|
||||||
|
$this->assertEquals(true, $user->getPreferenceValue('theme.collapsed_sidebar'));
|
||||||
|
$this->assertEquals(false, $user->getPreferenceValue('theme.mini_sidebar'));
|
||||||
|
$this->assertEquals('agendaDay', $user->getPreferenceValue('calendar.initial_view'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -383,6 +383,23 @@
|
|||||||
<source>label.theme.mini_sidebar</source>
|
<source>label.theme.mini_sidebar</source>
|
||||||
<target>Aktiviert die minimierte Version der linken Navigationsleiste</target>
|
<target>Aktiviert die minimierte Version der linken Navigationsleiste</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="label.calendar.initial_view">
|
||||||
|
<source>label.calendar.initial_view</source>
|
||||||
|
<target>Initiale Darstellung des Kalenders</target>
|
||||||
|
</trans-unit>
|
||||||
|
<!-- Options for user-preference label.calendar.initial_view -->
|
||||||
|
<trans-unit id="month">
|
||||||
|
<source>month</source>
|
||||||
|
<target>Monat</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="agendaWeek">
|
||||||
|
<source>agendaWeek</source>
|
||||||
|
<target>Woche</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="agendaDay">
|
||||||
|
<source>agendaDay</source>
|
||||||
|
<target>Tag</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Help - Manual
|
Help - Manual
|
||||||
|
|||||||
@@ -383,6 +383,23 @@
|
|||||||
<source>label.theme.mini_sidebar</source>
|
<source>label.theme.mini_sidebar</source>
|
||||||
<target>Toggle the size of the left sidebar's header (full or collapse)</target>
|
<target>Toggle the size of the left sidebar's header (full or collapse)</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="label.calendar.initial_view">
|
||||||
|
<source>label.calendar.initial_view</source>
|
||||||
|
<target>Initial calendar view</target>
|
||||||
|
</trans-unit>
|
||||||
|
<!-- Options for user-preference label.calendar.initial_view -->
|
||||||
|
<trans-unit id="month">
|
||||||
|
<source>month</source>
|
||||||
|
<target>Month</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="agendaWeek">
|
||||||
|
<source>agendaWeek</source>
|
||||||
|
<target>Week</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="agendaDay">
|
||||||
|
<source>agendaDay</source>
|
||||||
|
<target>Day</target>
|
||||||
|
</trans-unit>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Help - Manual
|
Help - Manual
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Kimai 2 provides a calendar view, which displays your timesheet entries in a easy readable format.
|
Kimai 2 provides a calendar view, which displays your timesheet entries in a easy readable format.
|
||||||
You can choose between a monthly, weekly and daily view.
|
You can choose between a monthly, weekly and daily view.
|
||||||
|
|
||||||
The calendar view look and feel is configured with the config keys below `kimai.calendar` in `kimai.yaml`:
|
The calendar view look and feel is configured with the config keys below `kimai.calendar` in `kimai.yaml` / your [local.yaml](configurations.md):
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
kimai:
|
kimai:
|
||||||
@@ -22,7 +22,14 @@ kimai:
|
|||||||
- `businessHours.begin` the start time of your working day, which will be highlighted in the weekly and daily view (default: 08:00 / 8am)
|
- `businessHours.begin` the start time of your working day, which will be highlighted in the weekly and daily view (default: 08:00 / 8am)
|
||||||
- `businessHours.end` the end time of your working day, which will be highlighted in the weekly and daily view (default: 20:00 / 8pm)
|
- `businessHours.end` the end time of your working day, which will be highlighted in the weekly and daily view (default: 20:00 / 8pm)
|
||||||
|
|
||||||
#### Integrating google calender
|
## Initial view
|
||||||
|
|
||||||
|
The initial view for the calendar is `month`.
|
||||||
|
It is a user specific setting and each user can configure it in his _User profile_ at _Preferences_.
|
||||||
|
|
||||||
|
Available options are: `month`, `agendaWeek`, `agendaDay`
|
||||||
|
|
||||||
|
## Integrating google calender
|
||||||
|
|
||||||
If you want to embed Google calendars e.g. to display regional holidays or company events you can import (multiple) Google calendars.
|
If you want to embed Google calendars e.g. to display regional holidays or company events you can import (multiple) Google calendars.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user