use pre-defined icons in menu as well (#913)
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
namespace App\EventSubscriber;
|
||||
|
||||
use App\Event\ConfigureMainMenuEvent;
|
||||
use App\Twig\IconExtension;
|
||||
use KevinPapst\AdminLTEBundle\Event\SidebarMenuEvent;
|
||||
use KevinPapst\AdminLTEBundle\Model\MenuItemModel;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
@@ -18,20 +19,21 @@ use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
|
||||
/**
|
||||
* Menu event subscriber is creating the Kimai default menu structure.
|
||||
*/
|
||||
class MenuSubscriber implements EventSubscriberInterface
|
||||
final class MenuSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
/**
|
||||
* @var AuthorizationCheckerInterface
|
||||
*/
|
||||
private $security;
|
||||
|
||||
/**
|
||||
* MenuSubscriber constructor.
|
||||
* @param AuthorizationCheckerInterface $security
|
||||
* @var IconExtension
|
||||
*/
|
||||
private $icons;
|
||||
|
||||
public function __construct(AuthorizationCheckerInterface $security)
|
||||
{
|
||||
$this->security = $security;
|
||||
$this->icons = new IconExtension();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,28 +65,28 @@ class MenuSubscriber implements EventSubscriberInterface
|
||||
/**
|
||||
* @param SidebarMenuEvent $menu
|
||||
*/
|
||||
protected function configureMainMenu(SidebarMenuEvent $menu)
|
||||
private function configureMainMenu(SidebarMenuEvent $menu)
|
||||
{
|
||||
$auth = $this->security;
|
||||
|
||||
if ($auth->isGranted('view_own_timesheet')) {
|
||||
$menu->addItem(
|
||||
new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], 'fas fa-clock')
|
||||
new MenuItemModel('timesheet', 'menu.timesheet', 'timesheet', [], $this->getIcon('timesheet'))
|
||||
);
|
||||
$menu->addItem(
|
||||
new MenuItemModel('calendar', 'calendar.title', 'calendar', [], 'far fa-calendar-alt')
|
||||
new MenuItemModel('calendar', 'calendar.title', 'calendar', [], $this->getIcon('calendar'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('view_invoice')) {
|
||||
$menu->addItem(
|
||||
new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], 'fas fa-file-invoice')
|
||||
new MenuItemModel('invoice', 'menu.invoice', 'invoice', [], $this->getIcon('invoice'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('view_export')) {
|
||||
$menu->addItem(
|
||||
new MenuItemModel('export', 'menu.export', 'export', [], 'fas fa-file-export')
|
||||
new MenuItemModel('export', 'menu.export', 'export', [], $this->getIcon('export'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -92,31 +94,31 @@ class MenuSubscriber implements EventSubscriberInterface
|
||||
/**
|
||||
* @param MenuItemModel $menu
|
||||
*/
|
||||
protected function configureAdminMenu(MenuItemModel $menu)
|
||||
private function configureAdminMenu(MenuItemModel $menu)
|
||||
{
|
||||
$auth = $this->security;
|
||||
|
||||
if ($auth->isGranted('view_other_timesheet')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('timesheet_admin', 'menu.admin_timesheet', 'admin_timesheet', [], 'fas fa-user-clock')
|
||||
new MenuItemModel('timesheet_admin', 'menu.admin_timesheet', 'admin_timesheet', [], $this->getIcon('timesheet-team'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('view_customer')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('customer_admin', 'menu.admin_customer', 'admin_customer', [], 'fas fa-user-tie')
|
||||
new MenuItemModel('customer_admin', 'menu.admin_customer', 'admin_customer', [], $this->getIcon('customer'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('view_project')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('project_admin', 'menu.admin_project', 'admin_project', [], 'fas fa-project-diagram')
|
||||
new MenuItemModel('project_admin', 'menu.admin_project', 'admin_project', [], $this->getIcon('project'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('view_activity')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('activity_admin', 'menu.admin_activity', 'admin_activity', [], 'fas fa-tasks')
|
||||
new MenuItemModel('activity_admin', 'menu.admin_activity', 'admin_activity', [], $this->getIcon('activity'))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -130,26 +132,31 @@ class MenuSubscriber implements EventSubscriberInterface
|
||||
/**
|
||||
* @param MenuItemModel $menu
|
||||
*/
|
||||
protected function configureSystemMenu(MenuItemModel $menu)
|
||||
private function configureSystemMenu(MenuItemModel $menu)
|
||||
{
|
||||
$auth = $this->security;
|
||||
|
||||
if ($auth->isGranted('view_user')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('user_admin', 'menu.admin_user', 'admin_user', [], 'fas fa-users')
|
||||
new MenuItemModel('user_admin', 'menu.admin_user', 'admin_user', [], $this->getIcon('user'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('plugins')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('plugins', 'menu.plugin', 'plugins', [], 'fas fa-plug')
|
||||
new MenuItemModel('plugins', 'menu.plugin', 'plugins', [], $this->getIcon('plugin'))
|
||||
);
|
||||
}
|
||||
|
||||
if ($auth->isGranted('system_configuration')) {
|
||||
$menu->addChild(
|
||||
new MenuItemModel('system_configuration', 'menu.system_configuration', 'system_configuration', [], 'fas fa-cogs')
|
||||
new MenuItemModel('system_configuration', 'menu.system_configuration', 'system_configuration', [], $this->getIcon('configuration'))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getIcon(string $icon)
|
||||
{
|
||||
return $this->icons->icon($icon, $icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,61 +45,6 @@ class Extensions extends AbstractExtension
|
||||
*/
|
||||
protected $moneyFormatter;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected static $icons = [
|
||||
'activity' => 'fas fa-tasks',
|
||||
'admin' => 'fas fa-wrench',
|
||||
'calendar' => 'far fa-calendar-alt',
|
||||
'customer' => 'fas fa-user-tie',
|
||||
'copy' => 'far fa-copy',
|
||||
'create' => 'far fa-plus-square',
|
||||
'dashboard' => 'fas fa-tachometer-alt',
|
||||
'delete' => 'far fa-trash-alt',
|
||||
'download' => 'fas fa-download',
|
||||
'duration' => 'far fa-hourglass',
|
||||
'edit' => 'far fa-edit',
|
||||
'filter' => 'fas fa-filter',
|
||||
'help' => 'far fa-question-circle',
|
||||
'invoice' => 'fas fa-file-invoice',
|
||||
'list' => 'fas fa-list',
|
||||
'logout' => 'fas fa-sign-out-alt',
|
||||
'manual' => 'fas fa-book',
|
||||
'money' => 'far fa-money-bill-alt',
|
||||
'print' => 'fas fa-print',
|
||||
'project' => 'fas fa-project-diagram',
|
||||
'repeat' => 'fas fa-redo-alt',
|
||||
'start' => 'fas fa-play-circle',
|
||||
'start-small' => 'far fa-play-circle',
|
||||
'stop' => 'fas fa-stop',
|
||||
'stop-small' => 'far fa-stop-circle',
|
||||
'timesheet' => 'fas fa-clock',
|
||||
'trash' => 'far fa-trash-alt',
|
||||
'user' => 'fas fa-users',
|
||||
'visibility' => 'far fa-eye',
|
||||
'settings' => 'fas fa-cog',
|
||||
'export' => 'fas fa-file-export',
|
||||
'pdf' => 'fas fa-file-pdf',
|
||||
'csv' => 'fas fa-table',
|
||||
'ods' => 'fas fa-table',
|
||||
'xlsx' => 'fas fa-file-excel',
|
||||
'on' => 'fas fa-toggle-on',
|
||||
'off' => 'fas fa-toggle-off',
|
||||
'audit' => 'fas fa-history',
|
||||
'home' => 'fas fa-home',
|
||||
'shop' => 'fas fa-shopping-cart',
|
||||
'about' => 'fas fa-info-circle',
|
||||
'debug' => 'far fa-file-alt',
|
||||
'profile-stats' => 'far fa-chart-bar',
|
||||
'profile' => 'fas fa-user-edit',
|
||||
'warning' => 'fas fa-exclamation-triangle',
|
||||
'permissions' => 'fas fa-user-lock',
|
||||
'back' => 'fas fa-long-arrow-alt-left',
|
||||
'tag' => 'fas fa-tags',
|
||||
'avatar' => 'fas fa-user'
|
||||
];
|
||||
|
||||
/**
|
||||
* @param LocaleSettings $localeSettings
|
||||
*/
|
||||
@@ -119,7 +64,6 @@ class Extensions extends AbstractExtension
|
||||
new TwigFilter('money', [$this, 'money']),
|
||||
new TwigFilter('currency', [$this, 'currency']),
|
||||
new TwigFilter('country', [$this, 'country']),
|
||||
new TwigFilter('icon', [$this, 'icon']),
|
||||
new TwigFilter('docu_link', [$this, 'documentationLink']),
|
||||
];
|
||||
}
|
||||
@@ -204,16 +148,6 @@ class Extensions extends AbstractExtension
|
||||
return Intl::getRegionBundle()->getCountryName($country);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $default
|
||||
* @return string
|
||||
*/
|
||||
public function icon($name, $default = '')
|
||||
{
|
||||
return self::$icons[$name] ?? $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @return string
|
||||
|
||||
89
src/Twig/IconExtension.php
Normal file
89
src/Twig/IconExtension.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?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\Twig;
|
||||
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
final class IconExtension extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
private static $icons = [
|
||||
'activity' => 'fas fa-tasks',
|
||||
'admin' => 'fas fa-wrench',
|
||||
'calendar' => 'far fa-calendar-alt',
|
||||
'customer' => 'fas fa-user-tie',
|
||||
'copy' => 'far fa-copy',
|
||||
'create' => 'far fa-plus-square',
|
||||
'dashboard' => 'fas fa-tachometer-alt',
|
||||
'delete' => 'far fa-trash-alt',
|
||||
'download' => 'fas fa-download',
|
||||
'duration' => 'far fa-hourglass',
|
||||
'edit' => 'far fa-edit',
|
||||
'filter' => 'fas fa-filter',
|
||||
'help' => 'far fa-question-circle',
|
||||
'invoice' => 'fas fa-file-invoice',
|
||||
'list' => 'fas fa-list',
|
||||
'logout' => 'fas fa-sign-out-alt',
|
||||
'manual' => 'fas fa-book',
|
||||
'money' => 'far fa-money-bill-alt',
|
||||
'print' => 'fas fa-print',
|
||||
'project' => 'fas fa-briefcase',
|
||||
'repeat' => 'fas fa-redo-alt',
|
||||
'start' => 'fas fa-play-circle',
|
||||
'start-small' => 'far fa-play-circle',
|
||||
'stop' => 'fas fa-stop',
|
||||
'stop-small' => 'far fa-stop-circle',
|
||||
'timesheet' => 'fas fa-clock',
|
||||
'trash' => 'far fa-trash-alt',
|
||||
'user' => 'fas fa-users',
|
||||
'visibility' => 'far fa-eye',
|
||||
'settings' => 'fas fa-cog',
|
||||
'export' => 'fas fa-file-export',
|
||||
'pdf' => 'fas fa-file-pdf',
|
||||
'csv' => 'fas fa-table',
|
||||
'ods' => 'fas fa-table',
|
||||
'xlsx' => 'fas fa-file-excel',
|
||||
'on' => 'fas fa-toggle-on',
|
||||
'off' => 'fas fa-toggle-off',
|
||||
'audit' => 'fas fa-history',
|
||||
'home' => 'fas fa-home',
|
||||
'shop' => 'fas fa-shopping-cart',
|
||||
'about' => 'fas fa-info-circle',
|
||||
'debug' => 'far fa-file-alt',
|
||||
'profile-stats' => 'far fa-chart-bar',
|
||||
'profile' => 'fas fa-user-edit',
|
||||
'warning' => 'fas fa-exclamation-triangle',
|
||||
'permissions' => 'fas fa-user-lock',
|
||||
'back' => 'fas fa-long-arrow-alt-left',
|
||||
'tag' => 'fas fa-tags',
|
||||
'avatar' => 'fas fa-user',
|
||||
'timesheet-team' => 'fas fa-user-clock',
|
||||
'plugin' => 'fas fa-plug',
|
||||
'configuration' => 'fas fa-cogs',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFilters()
|
||||
{
|
||||
return [
|
||||
new TwigFilter('icon', [$this, 'icon']),
|
||||
];
|
||||
}
|
||||
|
||||
public function icon(string $name, string $default = ''): string
|
||||
{
|
||||
return self::$icons[$name] ?? $default;
|
||||
}
|
||||
}
|
||||
@@ -50,7 +50,7 @@ class ExtensionsTest extends TestCase
|
||||
|
||||
public function testGetFilters()
|
||||
{
|
||||
$filters = ['duration', 'money', 'currency', 'country', 'icon', 'docu_link'];
|
||||
$filters = ['duration', 'money', 'currency', 'country', 'docu_link'];
|
||||
$sut = $this->getSut($this->localeDe);
|
||||
$twigFilters = $sut->getFilters();
|
||||
$this->assertCount(count($filters), $twigFilters);
|
||||
@@ -213,28 +213,6 @@ class ExtensionsTest extends TestCase
|
||||
return $record;
|
||||
}
|
||||
|
||||
public function testIcon()
|
||||
{
|
||||
$icons = [
|
||||
'user', 'customer', 'project', 'activity', 'admin', 'invoice', 'timesheet', 'dashboard', 'logout', 'trash',
|
||||
'delete', 'repeat', 'edit', 'manual', 'help', 'start', 'start-small', 'stop', 'stop-small', 'filter',
|
||||
'create', 'list', 'print', 'visibility', 'calendar', 'money', 'duration', 'download', 'copy', 'settings',
|
||||
'export', 'pdf', 'csv', 'ods', 'xlsx', 'on', 'off', 'audit', 'home', 'shop', 'about', 'debug', 'profile-stats'
|
||||
];
|
||||
|
||||
// test pre-defined icons
|
||||
$sut = $this->getSut($this->localeEn);
|
||||
foreach ($icons as $icon) {
|
||||
$result = $sut->icon($icon);
|
||||
$this->assertNotEmpty($result, 'Problem with icon definition: ' . $icon);
|
||||
$this->assertIsString($result);
|
||||
}
|
||||
|
||||
// test fallback will be returned
|
||||
$this->assertEquals('', $sut->icon('foo'));
|
||||
$this->assertEquals('bar', $sut->icon('foo', 'bar'));
|
||||
}
|
||||
|
||||
public function testDocuLink()
|
||||
{
|
||||
$data = [
|
||||
|
||||
58
tests/Twig/IconExtensionTest.php
Normal file
58
tests/Twig/IconExtensionTest.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?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\Tests\Twig;
|
||||
|
||||
use App\Twig\IconExtension;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Twig\TwigFilter;
|
||||
|
||||
/**
|
||||
* @covers \App\Twig\IconExtension
|
||||
*/
|
||||
class IconExtensionTest extends TestCase
|
||||
{
|
||||
public function testGetFilters()
|
||||
{
|
||||
$filters = ['icon'];
|
||||
$sut = new IconExtension();
|
||||
$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());
|
||||
}
|
||||
}
|
||||
|
||||
public function testIcon()
|
||||
{
|
||||
$icons = [
|
||||
'user', 'customer', 'project', 'activity', 'admin', 'invoice', 'timesheet', 'dashboard', 'logout', 'trash',
|
||||
'delete', 'repeat', 'edit', 'manual', 'help', 'start', 'start-small', 'stop', 'stop-small', 'filter',
|
||||
'create', 'list', 'print', 'visibility', 'calendar', 'money', 'duration', 'download', 'copy', 'settings',
|
||||
'export', 'pdf', 'csv', 'ods', 'xlsx', 'on', 'off', 'audit', 'home', 'shop', 'about', 'debug', 'profile-stats',
|
||||
'profile', 'warning', 'permissions', 'back', 'tag', 'avatar', 'timesheet-team', 'plugin', 'configuration'
|
||||
];
|
||||
|
||||
// test pre-defined icons
|
||||
$sut = new IconExtension();
|
||||
|
||||
foreach ($icons as $icon) {
|
||||
$result = $sut->icon($icon);
|
||||
$this->assertNotEmpty($result, 'Missing icon definition: ' . $icon);
|
||||
$this->assertIsString($result);
|
||||
}
|
||||
|
||||
// test fallback will be returned
|
||||
$this->assertEquals('', $sut->icon('foo'));
|
||||
$this->assertEquals('bar', $sut->icon('foo', 'bar'));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user