diff --git a/src/EventSubscriber/MenuSubscriber.php b/src/EventSubscriber/MenuSubscriber.php index 13f8d8ce..186f3c96 100644 --- a/src/EventSubscriber/MenuSubscriber.php +++ b/src/EventSubscriber/MenuSubscriber.php @@ -69,13 +69,13 @@ class MenuSubscriber implements EventSubscriberInterface if ($auth->isGranted('view_own_timesheet')) { $menu->addItem( - new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], 'far fa-clock') + new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], 'fas fa-clock') ); } if ($auth->isGranted('view_invoice')) { $menu->addItem( - new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], 'far fa-file-alt') + new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], 'fas fa-file-invoice') ); } diff --git a/src/Twig/DatatableExtensions.php b/src/Twig/DatatableExtensions.php new file mode 100644 index 00000000..1af42e0b --- /dev/null +++ b/src/Twig/DatatableExtensions.php @@ -0,0 +1,98 @@ +requestStack = $requestStack; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return [ + new TwigFunction('is_visible_column', [$this, 'isColumnVisible']), + new TwigFunction('is_datatable_configured', [$this, 'isDatatableConfigured']), + ]; + } + + /** + * @param string $dataTable + * @return bool + */ + public function isDatatableConfigured(string $dataTable) + { + $cookie = $this->getVisibilityCookieName($dataTable); + + return $this->requestStack->getCurrentRequest()->cookies->has($cookie); + } + + /** + * @param string $dataTable + * @return string + */ + protected function getVisibilityCookieName(string $dataTable) + { + return $dataTable . '_visibility'; + } + + /** + * This is only for datatables, do not use it outside this context. + * + * @param string $dataTable + * @param string $column + * @return bool + */ + public function isColumnVisible(string $dataTable, string $column) + { + // name handling is spread between here and datatables.html.twig (data_table_column_modal) + $cookie = $this->getVisibilityCookieName($dataTable); + + if (!isset($this->cookies[$cookie])) { + $visibility = false; + if ($this->requestStack->getCurrentRequest()->cookies->has($cookie)) { + $visibility = json_decode($this->requestStack->getCurrentRequest()->cookies->get($cookie), true); + } + $this->cookies[$cookie] = $visibility; + } + $values = $this->cookies[$cookie]; + + if (empty($values) || !is_array($values)) { + return true; + } + + if (isset($values[$column]) && $values[$column] === false) { + return false; + } + + return true; + } +} diff --git a/src/Twig/Extensions.php b/src/Twig/Extensions.php index b7df3cb2..0ec9667c 100644 --- a/src/Twig/Extensions.php +++ b/src/Twig/Extensions.php @@ -14,7 +14,6 @@ use App\Entity\Timesheet; use App\Utils\Duration; use App\Utils\LocaleSettings; use NumberFormatter; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Intl\Intl; use Twig\Extension\AbstractExtension; use Twig\TwigFilter; @@ -29,17 +28,14 @@ class Extensions extends AbstractExtension * @var LocaleSettings */ protected $localeSettings; - /** * @var string */ protected $locale; - /** * @var Duration */ protected $durationFormatter; - /** * @var NumberFormatter */ @@ -49,16 +45,6 @@ class Extensions extends AbstractExtension */ protected $moneyFormatter; - /** - * @var RequestStack - */ - protected $requestStack; - - /** - * @var array - */ - protected $cookies = []; - /** * @var string[] */ @@ -88,7 +74,7 @@ class Extensions extends AbstractExtension 'start-small' => 'fas fa-play-circle', 'stop' => 'fas fa-stop', 'stop-small' => 'far fa-stop-circle', - 'timesheet' => 'far fa-clock', + 'timesheet' => 'fas fa-clock', 'trash' => 'far fa-trash-alt', 'user' => 'fas fa-user', 'visibility' => 'far fa-eye', @@ -110,12 +96,10 @@ class Extensions extends AbstractExtension ]; /** - * @param RequestStack $requestStack * @param LocaleSettings $localeSettings */ - public function __construct(RequestStack $requestStack, LocaleSettings $localeSettings) + public function __construct(LocaleSettings $localeSettings) { - $this->requestStack = $requestStack; $this->localeSettings = $localeSettings; $this->durationFormatter = new Duration(); } @@ -142,8 +126,6 @@ class Extensions extends AbstractExtension { return [ new TwigFunction('locales', [$this, 'getLocales']), - new TwigFunction('is_visible_column', [$this, 'isColumnVisible']), - new TwigFunction('is_datatable_configured', [$this, 'isDatatableConfigured']), new TwigFunction('class_name', [$this, 'getClassName']), ]; } @@ -161,61 +143,6 @@ class Extensions extends AbstractExtension return get_class($object); } - /** - * @param string $dataTable - * @param string $size - * @return bool - */ - public function isDatatableConfigured(string $dataTable, string $size) - { - $cookie = $this->getVisibilityCookieName($dataTable, $size); - - return $this->requestStack->getCurrentRequest()->cookies->has($cookie); - } - - /** - * @param string $dataTable - * @param string $size - * @return string - */ - public function getVisibilityCookieName(string $dataTable, string $size) - { - return $dataTable . '_visibility' . $size; - } - - /** - * This is only for datatables, do not use it outside this context. - * - * @param string $dataTable - * @param string $column - * @param string $size - * @return bool - */ - public function isColumnVisible(string $dataTable, string $column, string $size) - { - // name handling is spread between here and datatables.html.twig (data_table_column_modal) - $cookie = $this->getVisibilityCookieName($dataTable, $size); - - if (!isset($this->cookies[$cookie])) { - $visibility = false; - if ($this->requestStack->getCurrentRequest()->cookies->has($cookie)) { - $visibility = json_decode($this->requestStack->getCurrentRequest()->cookies->get($cookie), true); - } - $this->cookies[$cookie] = $visibility; - } - $values = $this->cookies[$cookie]; - - if (empty($values) || !is_array($values)) { - return true; - } - - if (isset($values[$column]) && $values[$column] === false) { - return false; - } - - return true; - } - /** * Transforms seconds into a duration string. * diff --git a/src/Twig/TitleExtension.php b/src/Twig/TitleExtension.php new file mode 100644 index 00000000..d0aa9c57 --- /dev/null +++ b/src/Twig/TitleExtension.php @@ -0,0 +1,57 @@ +translator = $translator; + } + + /** + * {@inheritdoc} + */ + public function getFunctions() + { + return [ + new TwigFunction('get_title', [$this, 'generateTitle']), + ]; + } + + /** + * @param null|string $prefix + * @param string $delimiter + * @return string + */ + public function generateTitle(?string $prefix = null, string $delimiter = ' – ') + { + return ($prefix ?? '') . 'Kimai' . $delimiter . $this->translator->trans('time_tracking', [], 'messages'); + } +} diff --git a/templates/base.html.twig b/templates/base.html.twig index 67478b6a..b0a394b1 100644 --- a/templates/base.html.twig +++ b/templates/base.html.twig @@ -32,7 +32,7 @@ {% endblock %} {% block title %} - {{ 'browser.title'|trans }} + {{- get_title() -}} {% endblock %} {% block page_subtitle %}{% endblock %} diff --git a/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig b/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig index a63f131d..8b611193 100644 --- a/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig +++ b/templates/bundles/FOSUserBundle/Registration/confirmed.html.twig @@ -1,7 +1,7 @@ {% extends '@AdminLTE/FOSUserBundle/Registration/confirmed.html.twig' %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} -{% block title %}{{ 'browser.title'|trans }}{% endblock %} +{% block title %}{{- get_title() -}}{% endblock %} {% block head %} {{ parent() }} diff --git a/templates/bundles/FOSUserBundle/Registration/register.html.twig b/templates/bundles/FOSUserBundle/Registration/register.html.twig index 74deca46..b80e04a2 100644 --- a/templates/bundles/FOSUserBundle/Registration/register.html.twig +++ b/templates/bundles/FOSUserBundle/Registration/register.html.twig @@ -1,7 +1,7 @@ {% extends '@AdminLTE/FOSUserBundle/Registration/register.html.twig' %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} -{% block title %}{{ 'browser.title'|trans }}{% endblock %} +{% block title %}{{- get_title() -}}{% endblock %} {% block head %} {{ parent() }} diff --git a/templates/bundles/FOSUserBundle/Resetting/request.html.twig b/templates/bundles/FOSUserBundle/Resetting/request.html.twig index e766ef08..baa6fe25 100644 --- a/templates/bundles/FOSUserBundle/Resetting/request.html.twig +++ b/templates/bundles/FOSUserBundle/Resetting/request.html.twig @@ -1,7 +1,7 @@ {% extends '@AdminLTE/FOSUserBundle/Resetting/request.html.twig' %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} -{% block title %}{{ 'browser.title'|trans }}{% endblock %} +{% block title %}{{- get_title() -}}{% endblock %} {% block head %} {{ parent() }} diff --git a/templates/bundles/FOSUserBundle/Security/login.html.twig b/templates/bundles/FOSUserBundle/Security/login.html.twig index 2929aa77..5b36d83f 100644 --- a/templates/bundles/FOSUserBundle/Security/login.html.twig +++ b/templates/bundles/FOSUserBundle/Security/login.html.twig @@ -1,7 +1,7 @@ {% extends '@AdminLTE/FOSUserBundle/Security/login.html.twig' %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} -{% block title %}{{ 'browser.title'|trans }}{% endblock %} +{% block title %}{{- get_title() -}}{% endblock %} {% block login_box_icon %} diff --git a/templates/bundles/FOSUserBundle/layout.html.twig b/templates/bundles/FOSUserBundle/layout.html.twig index 9b783c76..fa41c894 100644 --- a/templates/bundles/FOSUserBundle/layout.html.twig +++ b/templates/bundles/FOSUserBundle/layout.html.twig @@ -1,7 +1,7 @@ {% extends '@AdminLTE/FOSUserBundle/layout.html.twig' %} {% block logo_login %}{% include 'partials/logo_login.html.twig' %}{% endblock %} -{% block title %}{{ 'browser.title'|trans }}{% endblock %} +{% block title %}{{- get_title() -}}{% endblock %} {% block head %} {{ parent() }} diff --git a/templates/macros/datatables.html.twig b/templates/macros/datatables.html.twig index 7f4fa374..3e760347 100644 --- a/templates/macros/datatables.html.twig +++ b/templates/macros/datatables.html.twig @@ -12,7 +12,7 @@ {% for title, class in entries %} {% if 'alwaysVisible' not in class %}
- +
{% endif %} @@ -45,9 +45,9 @@ {% endif %} {% endfor %} {% else %} - {% if not is_visible_column(name, column, '') %} + {% if not is_visible_column(name, column) %} {% set classes = classes ~ ' hidden' %} - {% elseif not is_datatable_configured(name, '') %} + {% elseif not is_datatable_configured(name) %} {% for tmp in classes|split(' ') %} {% if 'hidden' == tmp %} {% set classes = classes|replace({(tmp): ''}) %} diff --git a/templates/partials/logo_login.html.twig b/templates/partials/logo_login.html.twig index d3276caf..efff5158 100644 --- a/templates/partials/logo_login.html.twig +++ b/templates/partials/logo_login.html.twig @@ -1 +1 @@ -Kimai
TimeTracking +{{- get_title('', '
')|raw -}} diff --git a/tests/Controller/SecurityControllerTest.php b/tests/Controller/SecurityControllerTest.php index 8f14ba55..ce4423f3 100644 --- a/tests/Controller/SecurityControllerTest.php +++ b/tests/Controller/SecurityControllerTest.php @@ -36,7 +36,7 @@ class SecurityControllerTest extends ControllerBaseTest $this->assertTrue($client->getResponse()->isSuccessful()); $content = $response->getContent(); - $this->assertContains('Kimai - Time Tracking', $content); + $this->assertContains('Kimai – Time Tracking', $content); $this->assertContains('
', $content); $this->assertContains('assertContains('assertTrue($response->isSuccessful()); $content = $response->getContent(); - $this->assertContains('Kimai - Time Tracking', $content); + $this->assertContains('Kimai – Time Tracking', $content); $this->assertContains('Register a new account', $content); $this->assertContains('', $content); $this->assertContains('assertTrue($client->getResponse()->isSuccessful()); $content = $client->getResponse()->getContent(); - $this->assertContains('Kimai - Time Tracking', $content); + $this->assertContains('Kimai – Time Tracking', $content); $this->assertContains('

Congrats example, your account is now activated.

', $content); $this->assertContains('', $content); } diff --git a/tests/Export/Renderer/AbstractRendererTest.php b/tests/Export/Renderer/AbstractRendererTest.php index 5da4bbf3..3c6a48fd 100644 --- a/tests/Export/Renderer/AbstractRendererTest.php +++ b/tests/Export/Renderer/AbstractRendererTest.php @@ -50,7 +50,7 @@ abstract class AbstractRendererTest extends KernelTestCase $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); $dateExtension = new DateExtensions($localeSettings); - $extensions = new Extensions($requestStack, $localeSettings); + $extensions = new Extensions($localeSettings); return new $classname($translator, $dateExtension, $extensions); } diff --git a/tests/Invoice/Renderer/AbstractRendererTest.php b/tests/Invoice/Renderer/AbstractRendererTest.php index 9c5cec81..7232e287 100644 --- a/tests/Invoice/Renderer/AbstractRendererTest.php +++ b/tests/Invoice/Renderer/AbstractRendererTest.php @@ -74,7 +74,7 @@ abstract class AbstractRendererTest extends KernelTestCase $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); $dateExtension = new DateExtensions($localeSettings); - $extensions = new Extensions($requestStack, $localeSettings); + $extensions = new Extensions($localeSettings); return new $classname($translator, $dateExtension, $extensions); } diff --git a/tests/Timesheet/UserDateTimeFactoryTest.php b/tests/Timesheet/UserDateTimeFactoryTest.php index 986c369b..6a981538 100644 --- a/tests/Timesheet/UserDateTimeFactoryTest.php +++ b/tests/Timesheet/UserDateTimeFactoryTest.php @@ -23,7 +23,7 @@ use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; */ class UserDateTimeFactoryTest extends TestCase { - public const TEST_TIMEZONE = 'Antarctica/DumontDUrville'; + public const TEST_TIMEZONE = 'Europe/London'; protected function createDateTimeFactory(string $timezone) { diff --git a/tests/Twig/DatatableExtensionsTest.php b/tests/Twig/DatatableExtensionsTest.php new file mode 100644 index 00000000..bce29d8f --- /dev/null +++ b/tests/Twig/DatatableExtensionsTest.php @@ -0,0 +1,46 @@ +setLocale($locale); + $requestStack = new RequestStack(); + $requestStack->push($request); + + return new DatatableExtensions($requestStack); + } + + public function testGetFunctions() + { + $functions = ['is_visible_column', 'is_datatable_configured']; + $sut = $this->getSut('de'); + $twigFunctions = $sut->getFunctions(); + $this->assertCount(count($functions), $twigFunctions); + $i = 0; + /** @var TwigFunction $function */ + foreach ($twigFunctions as $function) { + $this->assertInstanceOf(TwigFunction::class, $function); + $this->assertEquals($functions[$i++], $function->getName()); + } + } +} diff --git a/tests/Twig/ExtensionsTest.php b/tests/Twig/ExtensionsTest.php index af54b229..366d77e8 100644 --- a/tests/Twig/ExtensionsTest.php +++ b/tests/Twig/ExtensionsTest.php @@ -45,7 +45,7 @@ class ExtensionsTest extends TestCase $localeSettings = new LocaleSettings($requestStack, new LanguageFormattings($locales)); - return new Extensions($requestStack, $localeSettings); + return new Extensions($localeSettings); } public function testGetFilters() @@ -55,6 +55,7 @@ class ExtensionsTest extends TestCase $twigFilters = $sut->getFilters(); $this->assertCount(count($filters), $twigFilters); $i = 0; + /** @var TwigFilter $filter */ foreach ($twigFilters as $filter) { $this->assertInstanceOf(TwigFilter::class, $filter); $this->assertEquals($filters[$i++], $filter->getName()); @@ -63,11 +64,12 @@ class ExtensionsTest extends TestCase public function testGetFunctions() { - $functions = ['locales', 'is_visible_column', 'is_datatable_configured', 'class_name']; + $functions = ['locales', 'class_name']; $sut = $this->getSut($this->localeDe); $twigFunctions = $sut->getFunctions(); $this->assertCount(count($functions), $twigFunctions); $i = 0; + /** @var TwigFunction $filter */ foreach ($twigFunctions as $filter) { $this->assertInstanceOf(TwigFunction::class, $filter); $this->assertEquals($functions[$i++], $filter->getName()); diff --git a/tests/Twig/TitleExtensionTest.php b/tests/Twig/TitleExtensionTest.php new file mode 100644 index 00000000..bebe7dfa --- /dev/null +++ b/tests/Twig/TitleExtensionTest.php @@ -0,0 +1,52 @@ +getMockBuilder(TranslatorInterface::class)->getMock(); + $translator->method('trans')->willReturn('foo'); + + return new TitleExtension($translator); + } + + public function testGetFunctions() + { + $functions = ['get_title']; + $sut = $this->getSut(); + $twigFunctions = $sut->getFunctions(); + $this->assertCount(count($functions), $twigFunctions); + $i = 0; + /** @var TwigFunction $function */ + foreach ($twigFunctions as $function) { + $this->assertInstanceOf(TwigFunction::class, $function); + $this->assertEquals($functions[$i++], $function->getName()); + } + } + + public function testGetTitle() + { + $sut = $this->getSut(); + $this->assertEquals('Kimai – foo', $sut->generateTitle()); + $this->assertEquals('sdfsdf | Kimai – foo', $sut->generateTitle('sdfsdf | ')); + $this->assertEquals('Kimai ... foo', $sut->generateTitle('', ' ... ')); + $this->assertEquals('Kimai | foo', $sut->generateTitle(null, ' | ')); + } +} diff --git a/translations/messages.ar.xliff b/translations/messages.ar.xliff index 53ff3b06..42cea006 100755 --- a/translations/messages.ar.xliff +++ b/translations/messages.ar.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Time Tracking + + time_tracking + Time Tracking yes diff --git a/translations/messages.de.xliff b/translations/messages.de.xliff index 2311974b..179be442 100644 --- a/translations/messages.de.xliff +++ b/translations/messages.de.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Zeiterfassung + + time_tracking + Zeiterfassung yes diff --git a/translations/messages.en.xliff b/translations/messages.en.xliff index d5b0fef9..2ac1053a 100644 --- a/translations/messages.en.xliff +++ b/translations/messages.en.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Time Tracking + + time_tracking + Time Tracking yes diff --git a/translations/messages.es.xliff b/translations/messages.es.xliff index ff68cfc6..53ff9030 100644 --- a/translations/messages.es.xliff +++ b/translations/messages.es.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Control de Tiempo + + time_tracking + Control de Tiempo yes diff --git a/translations/messages.fr.xliff b/translations/messages.fr.xliff index de95e267..1ece3db0 100644 --- a/translations/messages.fr.xliff +++ b/translations/messages.fr.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Suivi des temps + + time_tracking + Suivi des temps yes diff --git a/translations/messages.hu.xliff b/translations/messages.hu.xliff index 7199c4d5..07408df0 100644 --- a/translations/messages.hu.xliff +++ b/translations/messages.hu.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Időrögzítő + + time_tracking + Időrögzítő yes diff --git a/translations/messages.it.xliff b/translations/messages.it.xliff index 64daa77a..79a1f29e 100755 --- a/translations/messages.it.xliff +++ b/translations/messages.it.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Time Tracking + + time_tracking + Time Tracking yes diff --git a/translations/messages.pt_BR.xliff b/translations/messages.pt_BR.xliff index 4e0e308b..34cd1351 100644 --- a/translations/messages.pt_BR.xliff +++ b/translations/messages.pt_BR.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Time Tracking + + time_tracking + Time Tracking yes diff --git a/translations/messages.ru.xliff b/translations/messages.ru.xliff index e7dbadbb..d06ee2de 100644 --- a/translations/messages.ru.xliff +++ b/translations/messages.ru.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Учет времени + + time_tracking + Учет времени yes diff --git a/translations/messages.sv.xliff b/translations/messages.sv.xliff index b2aefa03..590b7e58 100644 --- a/translations/messages.sv.xliff +++ b/translations/messages.sv.xliff @@ -5,9 +5,9 @@ - - browser.title - Kimai - Tidsredovisning + + time_tracking + Tidsredovisning yes