Release 2.5.0 (#4454)
- added command to list users - corrected wrong german translation - work contract validations - prevent error with missing params - use collapsible, minor UI improvement - added classes to target menu buttons in custom rules - disable webpack notifier, incompatible with mac arm - use explicit menu service to generate menu - bump to fontawesome 6 and replace restart icon - change repeat icon for recent activities - moved user bookmarks (favorites) to top nav - fix totp seconds window (leeway) - new migration to fix remaining user preferences with dots in name - remove duplicate named column in user screen - unify and added translations - added missing filter and tags to InvoiceSecurity
This commit is contained in:
@@ -170,6 +170,7 @@ $fixer
|
|||||||
->setFinder(
|
->setFinder(
|
||||||
PhpCsFixer\Finder::create()
|
PhpCsFixer\Finder::create()
|
||||||
->in([
|
->in([
|
||||||
|
__DIR__ . '/migrations/',
|
||||||
__DIR__ . '/src/',
|
__DIR__ . '/src/',
|
||||||
__DIR__ . '/tests/',
|
__DIR__ . '/tests/',
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -43,3 +43,21 @@ h1.navbar-brand a {
|
|||||||
.navbar {
|
.navbar {
|
||||||
--tblr-navbar-brand-font-size: 1rem;
|
--tblr-navbar-brand-font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* user shortcuts dropdown */
|
||||||
|
.user-shortcuts {
|
||||||
|
.dropdown-menu-card {
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
.user-shortcuts-icon {
|
||||||
|
background-color: var(--tblr-bg-surface-secondary);
|
||||||
|
color: var(--tblr-gray-500);
|
||||||
|
height: 3.125rem;
|
||||||
|
width: 3.125rem;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ table.dataTable {
|
|||||||
thead .sorting_asc:after,
|
thead .sorting_asc:after,
|
||||||
thead .sorting_desc:after {
|
thead .sorting_desc:after {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
font-family: 'Font Awesome 5 Free';
|
font-family: 'Font Awesome 6 Free';
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
"friendsofsymfony/rest-bundle": "^3.0",
|
"friendsofsymfony/rest-bundle": "^3.0",
|
||||||
"gedmo/doctrine-extensions": "^3.6",
|
"gedmo/doctrine-extensions": "^3.6",
|
||||||
"jms/serializer-bundle": "^5.0",
|
"jms/serializer-bundle": "^5.0",
|
||||||
"kevinpapst/tabler-bundle": "^1.0",
|
"kevinpapst/tabler-bundle": "dev-main",
|
||||||
"league/csv": "^9.4",
|
"league/csv": "^9.4",
|
||||||
"mpdf/mpdf": "^8.0",
|
"mpdf/mpdf": "^8.0",
|
||||||
"nelmio/api-doc-bundle": "^4.0",
|
"nelmio/api-doc-bundle": "^4.0",
|
||||||
|
|||||||
490
composer.lock
generated
490
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -8,9 +8,10 @@ scheb_two_factor:
|
|||||||
totp:
|
totp:
|
||||||
enabled: true
|
enabled: true
|
||||||
template: security/2fa.html.twig # Overwritten template
|
template: security/2fa.html.twig # Overwritten template
|
||||||
window: 1 # How many codes before/after the current one would be accepted as valid
|
leeway: 29 # How many seconds the code is valid
|
||||||
issuer: Kimai # Issuer name used in QR code
|
issuer: Kimai # Issuer name used in QR code
|
||||||
|
|
||||||
two_factor_condition: App\Security\TwoFactorCondition
|
two_factor_condition: App\Security\TwoFactorCondition
|
||||||
|
|
||||||
# FIXME add backup codes - https://symfony.com/bundles/SchebTwoFactorBundle/current/backup_codes.html
|
# TODO add: backup codes - https://symfony.com/bundles/SchebTwoFactorBundle/current/backup_codes.html
|
||||||
|
# TODO add: Trusted device feature - https://github.com/scheb/2fa/blob/6.x/doc/configuration.rst
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ tabler:
|
|||||||
profile: fas fa-user-edit
|
profile: fas fa-user-edit
|
||||||
profile-stats: far fa-chart-bar
|
profile-stats: far fa-chart-bar
|
||||||
project: fas fa-briefcase
|
project: fas fa-briefcase
|
||||||
repeat: fas fa-redo-alt
|
repeat: fas fa-repeat
|
||||||
reporting: far fa-chart-bar
|
reporting: far fa-chart-bar
|
||||||
report: far fa-chart-bar
|
report: far fa-chart-bar
|
||||||
review: fas fa-user-check
|
review: fas fa-user-check
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ final class Version20230126002049 extends AbstractMigration
|
|||||||
$this->addSql("UPDATE kimai2_configuration SET `value` = '15' WHERE `name` = 'timesheet.time_increment' and `value` = '0'");
|
$this->addSql("UPDATE kimai2_configuration SET `value` = '15' WHERE `name` = 'timesheet.time_increment' and `value` = '0'");
|
||||||
$this->addSql("UPDATE kimai2_configuration SET `value` = '5' WHERE `name` = 'timesheet.time_increment' and `value` IN ('1', '2', '3', '4')");
|
$this->addSql("UPDATE kimai2_configuration SET `value` = '5' WHERE `name` = 'timesheet.time_increment' and `value` IN ('1', '2', '3', '4')");
|
||||||
$this->addSql("UPDATE kimai2_configuration SET `value` = '0' WHERE `name` = 'user.registration'");
|
$this->addSql("UPDATE kimai2_configuration SET `value` = '0' WHERE `name` = 'user.registration'");
|
||||||
$this->addSql("UPDATE kimai2_roles SET `name` = UPPER(`name`)");
|
$this->addSql('UPDATE kimai2_roles SET `name` = UPPER(`name`)');
|
||||||
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'service-date' WHERE `renderer` = 'freelancer'");
|
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'service-date' WHERE `renderer` = 'freelancer'");
|
||||||
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'invoice' WHERE `renderer` = 'default'");
|
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'invoice' WHERE `renderer` = 'default'");
|
||||||
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'default' WHERE `renderer` = 'default-pdf'");
|
$this->addSql("UPDATE kimai2_invoice_templates SET `renderer` = 'default' WHERE `renderer` = 'default-pdf'");
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 DoctrineMigrations;
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
use App\Doctrine\AbstractMigration;
|
use App\Doctrine\AbstractMigration;
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 DoctrineMigrations;
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
use App\Doctrine\AbstractMigration;
|
use App\Doctrine\AbstractMigration;
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 DoctrineMigrations;
|
namespace DoctrineMigrations;
|
||||||
|
|
||||||
use Doctrine\DBAL\Schema\Schema;
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
|||||||
43
migrations/Version20231130000719.php
Normal file
43
migrations/Version20231130000719.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 DoctrineMigrations;
|
||||||
|
|
||||||
|
use Doctrine\DBAL\Schema\Schema;
|
||||||
|
use Doctrine\Migrations\AbstractMigration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @version 2.5.0
|
||||||
|
*/
|
||||||
|
final class Version20231130000719 extends AbstractMigration
|
||||||
|
{
|
||||||
|
public function getDescription(): string
|
||||||
|
{
|
||||||
|
return 'Fix user preferences with dots in the name';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function up(Schema $schema): void
|
||||||
|
{
|
||||||
|
// select u1.* from kimai2_user_preferences u1 where u1.name like '%.%' and exists(select 1 from kimai2_user_preferences u2 where u2.name = replace(u1.name, '.', '_') and u1.user_id = u2.user_id);
|
||||||
|
// select u1.* from kimai2_user_preferences u1 where u1.name like '%.%';
|
||||||
|
$this->addSql("delete u1 from kimai2_user_preferences u1 where u1.name like '%.%' and exists(select 1 from (SELECT name, user_id FROM kimai2_user_preferences WHERE name LIKE '%_%') u2 where u2.name = replace(u1.name, '.', '_') and u1.user_id = u2.user_id)");
|
||||||
|
$this->addSql("update kimai2_user_preferences set `name` = replace(`name`, '.', '_')");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(Schema $schema): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isTransactional(): bool
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
"@babel/core": "^7.19.6",
|
"@babel/core": "^7.19.6",
|
||||||
"@babel/eslint-parser": "^7.18.2",
|
"@babel/eslint-parser": "^7.18.2",
|
||||||
"@babel/preset-env": "^7.19.4",
|
"@babel/preset-env": "^7.19.4",
|
||||||
"@fortawesome/fontawesome-free": "^6.2.0",
|
"@fortawesome/fontawesome-free": "^6.5.0",
|
||||||
"@fullcalendar/bootstrap5": "^5.11",
|
"@fullcalendar/bootstrap5": "^5.11",
|
||||||
"@fullcalendar/core": "^5.11",
|
"@fullcalendar/core": "^5.11",
|
||||||
"@fullcalendar/daygrid": "^5.11",
|
"@fullcalendar/daygrid": "^5.11",
|
||||||
@@ -48,7 +48,6 @@
|
|||||||
"sass-loader": "^13.2",
|
"sass-loader": "^13.2",
|
||||||
"tom-select": "^2.2",
|
"tom-select": "^2.2",
|
||||||
"webpack": "^5.74.0",
|
"webpack": "^5.74.0",
|
||||||
"webpack-cli": "^4.10.0",
|
"webpack-cli": "^4.10.0"
|
||||||
"webpack-notifier": "^1.13"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
1
public/build/app.0ecb28c1.css
Normal file
1
public/build/app.0ecb28c1.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
|
|||||||
"/build/app.63b27bee.js"
|
"/build/app.63b27bee.js"
|
||||||
],
|
],
|
||||||
"css": [
|
"css": [
|
||||||
"/build/app.fc41168c.css"
|
"/build/app.0ecb28c1.css"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"export-pdf": {
|
"export-pdf": {
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"integrity": {
|
"integrity": {
|
||||||
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
|
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
|
||||||
"/build/app.63b27bee.js": "sha384-1CV+he7m+KfetJpq/DmRwKfUhKH4L7MImv7rRUz/mr/KNR3VkT0fQJHF7ViPTVYE",
|
"/build/app.63b27bee.js": "sha384-1CV+he7m+KfetJpq/DmRwKfUhKH4L7MImv7rRUz/mr/KNR3VkT0fQJHF7ViPTVYE",
|
||||||
"/build/app.fc41168c.css": "sha384-3Td9W7KogJoBiywzWOgpkPPNHEIT8/a/SkMZM5NgIRmuChj/3PeOKkOHVJQlhP2E",
|
"/build/app.0ecb28c1.css": "sha384-iCao48T4VAR0rv39D1+kCk8GCRtve2QDTH5gGq1I1TMXmy1xA/OPxjeBFgGKkRk+",
|
||||||
"/build/export-pdf.d367a32e.js": "sha384-Z5baqnzjI636nYFs4g63ViIKBZKRW4Jhv/7PQmTEQlqhfA7eK0vUMUtiyy0R5A9u",
|
"/build/export-pdf.d367a32e.js": "sha384-Z5baqnzjI636nYFs4g63ViIKBZKRW4Jhv/7PQmTEQlqhfA7eK0vUMUtiyy0R5A9u",
|
||||||
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
|
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
|
||||||
"/build/invoice.2604495e.js": "sha384-D6JvhGSqlx7z72b/qD3nF3QDXPy+XsCSRGtWfs1icjDKOcd2UzuXwuSa/E1Fg2TJ",
|
"/build/invoice.2604495e.js": "sha384-D6JvhGSqlx7z72b/qD3nF3QDXPy+XsCSRGtWfs1icjDKOcd2UzuXwuSa/E1Fg2TJ",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"build/app.css": "/build/app.fc41168c.css",
|
"build/app.css": "/build/app.0ecb28c1.css",
|
||||||
"build/app.js": "/build/app.63b27bee.js",
|
"build/app.js": "/build/app.63b27bee.js",
|
||||||
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
|
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
|
||||||
"build/export-pdf.js": "/build/export-pdf.d367a32e.js",
|
"build/export-pdf.js": "/build/export-pdf.d367a32e.js",
|
||||||
|
|||||||
49
src/Command/ListUserCommand.php
Normal file
49
src/Command/ListUserCommand.php
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
<?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\Command;
|
||||||
|
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Symfony\Component\Console\Attribute\AsCommand;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||||
|
|
||||||
|
#[AsCommand(name: 'kimai:user:list', description: 'List all users')]
|
||||||
|
final class ListUserCommand extends Command
|
||||||
|
{
|
||||||
|
public function __construct(private UserRepository $repository)
|
||||||
|
{
|
||||||
|
parent::__construct();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$output = new SymfonyStyle($input, $output);
|
||||||
|
$users = $this->repository->findAll();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$data[] = [
|
||||||
|
$user->getUserIdentifier(),
|
||||||
|
$user->getEmail(),
|
||||||
|
implode(', ', $user->getRoles()),
|
||||||
|
$user->isEnabled() ? 'X' : '',
|
||||||
|
$user->getPasswordRequestedAt()?->format('Y-m-d H:i:s')
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$header = ['Username', 'Email', 'Roles', 'Active', 'PW Reset'];
|
||||||
|
|
||||||
|
$output->table($header, $data);
|
||||||
|
|
||||||
|
return Command::SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,11 @@ class Constants
|
|||||||
/**
|
/**
|
||||||
* The current release version
|
* The current release version
|
||||||
*/
|
*/
|
||||||
public const VERSION = '2.4.1';
|
public const VERSION = '2.5.0';
|
||||||
/**
|
/**
|
||||||
* The current release: major * 10000 + minor * 100 + patch
|
* The current release: major * 10000 + minor * 100 + patch
|
||||||
*/
|
*/
|
||||||
public const VERSION_ID = 20401;
|
public const VERSION_ID = 20500;
|
||||||
/**
|
/**
|
||||||
* The software name
|
* The software name
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ final class UserController extends AbstractController
|
|||||||
$table->setReloadEvents('kimai.userUpdate');
|
$table->setReloadEvents('kimai.userUpdate');
|
||||||
|
|
||||||
$table->addColumn('avatar', ['class' => 'alwaysVisible w-avatar', 'title' => null, 'orderBy' => false]);
|
$table->addColumn('avatar', ['class' => 'alwaysVisible w-avatar', 'title' => null, 'orderBy' => false]);
|
||||||
$table->addColumn('user', ['class' => 'alwaysVisible', 'orderBy' => 'user']);
|
//$table->addColumn('user', ['class' => 'alwaysVisible', 'orderBy' => 'user']);
|
||||||
$table->addColumn('username', ['class' => 'd-none']);
|
$table->addColumn('username', ['class' => 'alwaysVisible']);
|
||||||
$table->addColumn('alias', ['class' => 'd-none']);
|
$table->addColumn('alias', ['class' => 'd-none']);
|
||||||
$table->addColumn('account_number', ['class' => 'd-none']);
|
$table->addColumn('account_number', ['class' => 'd-none']);
|
||||||
$table->addColumn('title', ['class' => 'd-none']);
|
$table->addColumn('title', ['class' => 'd-none']);
|
||||||
|
|||||||
@@ -9,13 +9,10 @@
|
|||||||
|
|
||||||
namespace App\EventSubscriber;
|
namespace App\EventSubscriber;
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use App\Event\ConfigureMainMenuEvent;
|
|
||||||
use App\Utils\MenuItemModel;
|
use App\Utils\MenuItemModel;
|
||||||
|
use App\Utils\MenuService;
|
||||||
use KevinPapst\TablerBundle\Event\MenuEvent;
|
use KevinPapst\TablerBundle\Event\MenuEvent;
|
||||||
use KevinPapst\TablerBundle\Model\MenuItemInterface;
|
use KevinPapst\TablerBundle\Model\MenuItemInterface;
|
||||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,7 +21,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|||||||
*/
|
*/
|
||||||
final class MenuBuilderSubscriber implements EventSubscriberInterface
|
final class MenuBuilderSubscriber implements EventSubscriberInterface
|
||||||
{
|
{
|
||||||
public function __construct(private EventDispatcherInterface $eventDispatcher, private Security $security)
|
public function __construct(private MenuService $menuService)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,15 +34,7 @@ final class MenuBuilderSubscriber implements EventSubscriberInterface
|
|||||||
|
|
||||||
public function onSetupNavbar(MenuEvent $event): void
|
public function onSetupNavbar(MenuEvent $event): void
|
||||||
{
|
{
|
||||||
$menuEvent = new ConfigureMainMenuEvent();
|
$menuEvent = $this->menuService->getKimaiMenu();
|
||||||
|
|
||||||
/** @var User $user */
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
|
|
||||||
// error pages don't have a user and will fail when is_granted() is called
|
|
||||||
if (null !== $user) {
|
|
||||||
$this->eventDispatcher->dispatch($menuEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($menuEvent->getMenu()->getChildren() as $child) {
|
foreach ($menuEvent->getMenu()->getChildren() as $child) {
|
||||||
if ($child->getRoute() === null && !$child->hasChildren()) {
|
if ($child->getRoute() === null && !$child->hasChildren()) {
|
||||||
|
|||||||
@@ -1,61 +0,0 @@
|
|||||||
<?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\EventSubscriber;
|
|
||||||
|
|
||||||
use App\Entity\User;
|
|
||||||
use App\Event\ConfigureMainMenuEvent;
|
|
||||||
use Symfony\Bundle\SecurityBundle\Security;
|
|
||||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
|
||||||
|
|
||||||
final class MenuFavoritesSubscriber implements EventSubscriberInterface
|
|
||||||
{
|
|
||||||
public function __construct(private Security $security)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function getSubscribedEvents(): array
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
ConfigureMainMenuEvent::class => ['onMainMenuConfigure', 90], // see MenuSubscriber
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onMainMenuConfigure(ConfigureMainMenuEvent $menuEvent): void
|
|
||||||
{
|
|
||||||
/** @var User|null $user */
|
|
||||||
$user = $this->security->getUser();
|
|
||||||
if (null === $user) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$userFavorites = $user->getPreferenceValue('favorite_routes');
|
|
||||||
if (!\is_string($userFavorites) || trim($userFavorites) === '') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$favMenu = $menuEvent->findById('favorites');
|
|
||||||
if ($favMenu === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$userFavorites = explode(',', $userFavorites);
|
|
||||||
foreach ($userFavorites as $fav) {
|
|
||||||
$tmp = $menuEvent->findById($fav);
|
|
||||||
if ($tmp !== null && !$tmp->hasChildren()) {
|
|
||||||
$favMenu->addChild(clone $tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($favMenu->hasChildren()) {
|
|
||||||
$favMenu->setExpanded(true);
|
|
||||||
$menuEvent->getTimesheetMenu()?->setExpanded(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
46
src/Twig/Runtime/MenuExtension.php
Normal file
46
src/Twig/Runtime/MenuExtension.php
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<?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\Runtime;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Utils\MenuItemModel;
|
||||||
|
use App\Utils\MenuService;
|
||||||
|
use Twig\Extension\RuntimeExtensionInterface;
|
||||||
|
|
||||||
|
final class MenuExtension implements RuntimeExtensionInterface
|
||||||
|
{
|
||||||
|
public function __construct(private MenuService $menuService)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<MenuItemModel>
|
||||||
|
*/
|
||||||
|
public function getUserShortcuts(User $user): array
|
||||||
|
{
|
||||||
|
$shortcuts = $user->getPreferenceValue('favorite_routes');
|
||||||
|
if (!\is_string($shortcuts) || trim($shortcuts) === '') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$favMenu = [];
|
||||||
|
|
||||||
|
$shortcuts = explode(',', $shortcuts);
|
||||||
|
$menu = $this->menuService->getKimaiMenu();
|
||||||
|
foreach ($shortcuts as $fav) {
|
||||||
|
$tmp = $menu->findById($fav);
|
||||||
|
if ($tmp !== null && !$tmp->hasChildren()) {
|
||||||
|
$favMenu[] = clone $tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $favMenu;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ namespace App\Twig;
|
|||||||
|
|
||||||
use App\Twig\Runtime\EncoreExtension;
|
use App\Twig\Runtime\EncoreExtension;
|
||||||
use App\Twig\Runtime\MarkdownExtension;
|
use App\Twig\Runtime\MarkdownExtension;
|
||||||
|
use App\Twig\Runtime\MenuExtension;
|
||||||
use App\Twig\Runtime\QrCodeExtension;
|
use App\Twig\Runtime\QrCodeExtension;
|
||||||
use App\Twig\Runtime\ThemeExtension;
|
use App\Twig\Runtime\ThemeExtension;
|
||||||
use App\Twig\Runtime\TimesheetExtension;
|
use App\Twig\Runtime\TimesheetExtension;
|
||||||
@@ -37,6 +38,7 @@ final class RuntimeExtensions extends AbstractExtension
|
|||||||
new TwigFunction('render_widget', [WidgetExtension::class, 'renderWidget'], ['is_safe' => ['html'], 'needs_environment' => true]),
|
new TwigFunction('render_widget', [WidgetExtension::class, 'renderWidget'], ['is_safe' => ['html'], 'needs_environment' => true]),
|
||||||
new TwigFunction('icon', [RuntimeExtension::class, 'createIcon'], ['is_safe' => ['html']]),
|
new TwigFunction('icon', [RuntimeExtension::class, 'createIcon'], ['is_safe' => ['html']]),
|
||||||
new TwigFunction('qr_code_data_uri', [QrCodeExtension::class, 'qrCodeDataUriFunction']),
|
new TwigFunction('qr_code_data_uri', [QrCodeExtension::class, 'qrCodeDataUriFunction']),
|
||||||
|
new TwigFunction('user_shortcuts', [MenuExtension::class, 'getUserShortcuts']),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ final class InvoicePolicy implements SecurityPolicyInterface
|
|||||||
$this->policy = new ChainPolicy();
|
$this->policy = new ChainPolicy();
|
||||||
$this->policy->addPolicy(new DefaultPolicy());
|
$this->policy->addPolicy(new DefaultPolicy());
|
||||||
$this->policy->addPolicy(new SecurityPolicy(
|
$this->policy->addPolicy(new SecurityPolicy(
|
||||||
['block', 'if', 'for', 'set', 'extends'],
|
['block', 'if', 'for', 'set', 'extends', 'import'],
|
||||||
[
|
[
|
||||||
// =================================================================
|
// =================================================================
|
||||||
// vendor/twig/twig/src/Extension/CoreExtension.php
|
// vendor/twig/twig/src/Extension/CoreExtension.php
|
||||||
@@ -102,9 +102,16 @@ final class InvoicePolicy implements SecurityPolicyInterface
|
|||||||
'currency_symbol',
|
'currency_symbol',
|
||||||
'language_name',
|
'language_name',
|
||||||
'locale_name',
|
'locale_name',
|
||||||
|
'timezone_name',
|
||||||
'format_currency',
|
'format_currency',
|
||||||
'format_number',
|
'format_number',
|
||||||
'format_*_number',
|
'format_decimal_number',
|
||||||
|
'format_currency_number',
|
||||||
|
'format_percent_number',
|
||||||
|
'format_scientific_number',
|
||||||
|
'format_spellout_number',
|
||||||
|
'format_ordinal_number',
|
||||||
|
'format_duration_number',
|
||||||
'format_datetime',
|
'format_datetime',
|
||||||
'format_date',
|
'format_date',
|
||||||
'format_time',
|
'format_time',
|
||||||
|
|||||||
40
src/Utils/MenuService.php
Normal file
40
src/Utils/MenuService.php
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?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\Utils;
|
||||||
|
|
||||||
|
use App\Entity\User;
|
||||||
|
use App\Event\ConfigureMainMenuEvent;
|
||||||
|
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Bundle\SecurityBundle\Security;
|
||||||
|
|
||||||
|
final class MenuService
|
||||||
|
{
|
||||||
|
private ?ConfigureMainMenuEvent $menuEvent = null;
|
||||||
|
|
||||||
|
public function __construct(private EventDispatcherInterface $eventDispatcher, private Security $security)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKimaiMenu(): ConfigureMainMenuEvent
|
||||||
|
{
|
||||||
|
if (null === $this->menuEvent) {
|
||||||
|
$this->menuEvent = new ConfigureMainMenuEvent();
|
||||||
|
/** @var User $user */
|
||||||
|
$user = $this->security->getUser();
|
||||||
|
|
||||||
|
// error pages don't have a user and will fail when is_granted() is called
|
||||||
|
if (null !== $user) {
|
||||||
|
$this->eventDispatcher->dispatch($this->menuEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->menuEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,7 @@
|
|||||||
{% if is_granted('view_own_timesheet') %}
|
{% if is_granted('view_own_timesheet') %}
|
||||||
{% include 'partials/recent-activities.html.twig' %}
|
{% include 'partials/recent-activities.html.twig' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% include 'partials/user-shortcuts.html.twig' %}
|
||||||
{% block navbar_extensions_after %}
|
{% block navbar_extensions_after %}
|
||||||
{% set event = trigger(constant('App\\Event\\ThemeEvent::TOOLBAR')) %}
|
{% set event = trigger(constant('App\\Event\\ThemeEvent::TOOLBAR')) %}
|
||||||
{{ event.content|raw }}
|
{{ event.content|raw }}
|
||||||
|
|||||||
@@ -87,56 +87,8 @@
|
|||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if withWorkHourConfiguration %}
|
|
||||||
{% set expectedWeekTimes = user.workHoursMonday + user.workHoursTuesday + user.workHoursWednesday + user.workHoursThursday + user.workHoursFriday + user.workHoursSaturday + user.workHoursSunday %}
|
|
||||||
|
|
||||||
{% embed '@theme/embeds/card.html.twig' with {'collapsed': box_configuration.collapsed} %}
|
|
||||||
{% from "macros/status.html.twig" import status_duration %}
|
|
||||||
{% block box_title %}
|
|
||||||
{{ 'work_times_should'|trans }}
|
|
||||||
{{ status_duration(expectedWeekTimes|duration) }}
|
|
||||||
{% endblock %}
|
|
||||||
{% block box_body %}
|
|
||||||
<div class="datagrid">
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'agendaWeek'|trans }}</div>
|
|
||||||
<div class="datagrid-content">{{ expectedWeekTimes|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Monday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursMonday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Tuesday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursTuesday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Wednesday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursWednesday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Thursday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursThursday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Friday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursFriday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Saturday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursSaturday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="datagrid-item">
|
|
||||||
<div class="datagrid-title">{{ 'Sunday'|trans({}, 'system-configuration') }}</div>
|
|
||||||
<div class="datagrid-content">{{ user.workHoursSunday|duration }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
{% endembed %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if year is defined %}
|
{% if year is defined %}
|
||||||
{% embed '@theme/embeds/card.html.twig' with {'collapsed': box_configuration.collapsed, 'id': 'working_time_detail_box', 'fullsize': true} %}
|
{% embed '@theme/embeds/collapsible.html.twig' with {open: not box_configuration.collapsed, id: 'working_time_detail_box', border: false, item: {options: {bodyExtraClass: 'border-top'}, bodyClasses: 'p-0 table-responsive'}} %}
|
||||||
{% set yearShould = 0 %}
|
{% set yearShould = 0 %}
|
||||||
{% set yearIs = 0 %}
|
{% set yearIs = 0 %}
|
||||||
{% set approved = 0 %}
|
{% set approved = 0 %}
|
||||||
@@ -154,17 +106,14 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% from "macros/widgets.html.twig" import work_times_result, table_actions, card_tool_button, username %}
|
{% from "macros/widgets.html.twig" import work_times_result, table_actions, card_tool_button, username %}
|
||||||
{% from "macros/status.html.twig" import status_count %}
|
{% from "macros/status.html.twig" import status_count %}
|
||||||
{% block box_title %}
|
{% block title %}
|
||||||
{{ 'work_times'|trans }}
|
{{ 'work_times'|trans }}
|
||||||
{% if withWorkHourConfiguration %}
|
{% if withWorkHourConfiguration %}
|
||||||
|
|
||||||
{{ status_count(approved ~ '/' ~ year.months|length) }}
|
{{ status_count(approved ~ '/' ~ year.months|length) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block box_body_classes %}card-table table-responsive{% endblock %}
|
{% block body %}
|
||||||
{% block box_tools %}
|
|
||||||
{# {{ card_tool_button('visibility', {'onclick': "toggleDays(); return false;", 'id': 'toggleDaysIcon'}) }} #}
|
|
||||||
{% endblock %}
|
|
||||||
{% block box_body %}
|
|
||||||
<table id="working_times_details" class="table table-vcenter table-hover dataTable">
|
<table id="working_times_details" class="table table-vcenter table-hover dataTable">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -276,6 +225,51 @@
|
|||||||
{% endembed %}
|
{% endembed %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if withWorkHourConfiguration %}
|
||||||
|
{% set expectedWeekTimes = user.workHoursMonday + user.workHoursTuesday + user.workHoursWednesday + user.workHoursThursday + user.workHoursFriday + user.workHoursSaturday + user.workHoursSunday %}
|
||||||
|
|
||||||
|
{% embed '@theme/embeds/collapsible.html.twig' with {open: not box_configuration.collapsed, id: 'work_contract_should_preview', border: false, item: {options: {bodyExtraClass: 'border-top'}}} %}
|
||||||
|
{% from "macros/status.html.twig" import status_duration %}
|
||||||
|
{% block title %}
|
||||||
|
{{ 'work_times_should'|trans }}
|
||||||
|
|
||||||
|
{{ status_duration(expectedWeekTimes|duration) }}
|
||||||
|
{% endblock %}
|
||||||
|
{% block body %}
|
||||||
|
<div class="datagrid">
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Monday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursMonday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Tuesday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursTuesday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Wednesday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursWednesday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Thursday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursThursday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Friday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursFriday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Saturday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursSaturday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="datagrid-item">
|
||||||
|
<div class="datagrid-title">{{ 'Sunday'|trans({}, 'system-configuration') }}</div>
|
||||||
|
<div class="datagrid-content">{{ user.workHoursSunday|duration }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endembed %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% for controller in boxes %}
|
{% for controller in boxes %}
|
||||||
{{ render(controller(controller, {'year': year, 'boxConfiguration': box_configuration})) }}
|
{{ render(controller(controller, {'year': year, 'boxConfiguration': box_configuration})) }}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -277,7 +277,7 @@
|
|||||||
|
|
||||||
{% macro action_button(icon, values, type) %}
|
{% macro action_button(icon, values, type) %}
|
||||||
{% import '@theme/components/button.html.twig' as macro %}
|
{% import '@theme/components/button.html.twig' as macro %}
|
||||||
{% set values = values|merge({'tooltip_attr': 'data-toggle'}) %}
|
{% set values = (values ?? {})|merge({'tooltip_attr': 'data-toggle'}) %}
|
||||||
{{ macro.button(icon, values, type) }}
|
{{ macro.button(icon, values, type) }}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
{% if is_granted('start_own_timesheet') %}
|
{% if is_granted('start_own_timesheet') %}
|
||||||
{% set class = "btn-outline-white" %}
|
<div class="nav-item d-flex me-1 recent-activities">
|
||||||
{% if tabler_bundle.isDarkMode() or tabler_bundle.isNavbarOverlapping() %}
|
<a href="{{ path('favorites_timesheets') }}" class="nav-link px-0 remote-modal-load recent-activities-btn" data-modal-title="{{ 'recent.activities'|trans }}" tabindex="-1" aria-label="{{ 'recent.activities'|trans }}">
|
||||||
{% set class = "btn-dark" %}
|
{{ icon('repeat', true) }}
|
||||||
{% endif %}
|
|
||||||
<div class="nav-item d-flex me-sm-3 me-1">
|
|
||||||
<a href="{{ path('favorites_timesheets') }}" class="btn btn-icon {{ class}} px-0 remote-modal-load" data-modal-title="{{ 'recent.activities'|trans }}" tabindex="-1" aria-label="{{ 'recent.activities'|trans }}">
|
|
||||||
{{ icon('repeat') }}
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
{# fake entry, because at least one html template node is needed #}
|
{# fake entry, because at least one html template node is needed #}
|
||||||
{% set active_timesheets = [{'id': '000', 'begin': null, 'activity': {'name': ''}, 'project': {'name': '', 'customer': {'name': ''}}}] %}
|
{% set active_timesheets = [{'id': '000', 'begin': null, 'activity': {'name': ''}, 'project': {'name': '', 'customer': {'name': ''}}}] %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="nav-item d-flex me-sm-3 me-1">
|
<div class="nav-item d-flex me-1 ticktac">
|
||||||
<div class="btn-list">
|
<div class="btn-list">
|
||||||
{% set class = "btn-outline-white" %}
|
{% set class = "btn-outline-white" %}
|
||||||
{% if tabler_bundle.isDarkMode() or tabler_bundle.isNavbarOverlapping() %}
|
{% if tabler_bundle.isDarkMode() or tabler_bundle.isNavbarOverlapping() %}
|
||||||
|
|||||||
36
templates/partials/user-shortcuts.html.twig
Normal file
36
templates/partials/user-shortcuts.html.twig
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{% set user_shortcuts = user_shortcuts(app.user) %}
|
||||||
|
{% if user_shortcuts|length > 0 %}
|
||||||
|
<div class="nav-item dropdown d-flex me-1 user-shortcuts">
|
||||||
|
<a class="nav-link px-0 user-shortcuts-toggle" href="javascript:void(0);" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="true">
|
||||||
|
{{ icon('far fa-bookmark', true) }}
|
||||||
|
</a>
|
||||||
|
<div class="dropdown-menu dropdown-menu-end dropdown-menu-arrow dropdown-menu-card" data-bs-popper="static">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header text-nowrap">{{ 'favorite_routes'|trans }}</div>
|
||||||
|
<div class="card-body user-shortcuts-list scrollable-container p-0 pb-2">
|
||||||
|
<div class="row overflow-visible g-0">
|
||||||
|
{% for menu in user_shortcuts %}
|
||||||
|
{% if not loop.first and loop.index0 % 2 == 0 %}
|
||||||
|
</div>
|
||||||
|
<div class="row overflow-visible g-0">
|
||||||
|
{% endif %}
|
||||||
|
<div class="text-center pt-3 px-3 col">
|
||||||
|
<a href="{{ path(menu.route) }}" class="text-decoration-none">
|
||||||
|
<span class="user-shortcuts-icon rounded-circle mb-2">
|
||||||
|
<i class="{{ menu.icon|icon }} fs-2"></i>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
<a href="{{ path(menu.route) }}" class="nav-link">
|
||||||
|
{{- menu.label|trans -}}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% if user_shortcuts|length > 1 and user_shortcuts|length % 2 == 1 %}
|
||||||
|
<div class="pt-3 px-3 col"></div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
48
tests/Command/ListUserCommandTest.php
Normal file
48
tests/Command/ListUserCommandTest.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?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\Command;
|
||||||
|
|
||||||
|
use App\Command\ListUserCommand;
|
||||||
|
use App\Repository\UserRepository;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
|
||||||
|
use Symfony\Component\Console\Tester\CommandTester;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \App\Command\ListUserCommand
|
||||||
|
* @group integration
|
||||||
|
*/
|
||||||
|
class ListUserCommandTest extends KernelTestCase
|
||||||
|
{
|
||||||
|
public function testWithPlugins(): void
|
||||||
|
{
|
||||||
|
$commandTester = $this->getCommandTester();
|
||||||
|
$output = $commandTester->getDisplay();
|
||||||
|
$this->assertStringContainsString('Username Email Roles Active PW Reset', $output);
|
||||||
|
$this->assertStringContainsString('---------- ------- ------- -------- ----------', $output);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCommandTester(): CommandTester
|
||||||
|
{
|
||||||
|
$repository = $this->createMock(UserRepository::class);
|
||||||
|
$repository->method('findAll')->willReturn([]);
|
||||||
|
|
||||||
|
$kernel = self::bootKernel();
|
||||||
|
$application = new Application($kernel);
|
||||||
|
$application->add(new ListUserCommand($repository));
|
||||||
|
|
||||||
|
$command = $application->find('kimai:user:list');
|
||||||
|
$commandTester = new CommandTester($command);
|
||||||
|
$inputs = array_merge(['command' => $command->getName()], []);
|
||||||
|
$commandTester->execute($inputs);
|
||||||
|
|
||||||
|
return $commandTester;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?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\EventSubscriber;
|
|
||||||
|
|
||||||
use App\Event\ConfigureMainMenuEvent;
|
|
||||||
use App\EventSubscriber\MenuFavoritesSubscriber;
|
|
||||||
use App\EventSubscriber\MenuSubscriber;
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @covers \App\EventSubscriber\MenuFavoritesSubscriber
|
|
||||||
*/
|
|
||||||
class MenuFavoritesSubscriberTest extends TestCase
|
|
||||||
{
|
|
||||||
public function testGetSubscribedEvents(): void
|
|
||||||
{
|
|
||||||
$events = MenuFavoritesSubscriber::getSubscribedEvents();
|
|
||||||
$this->assertArrayHasKey(ConfigureMainMenuEvent::class, $events);
|
|
||||||
$methodName = $events[ConfigureMainMenuEvent::class][0];
|
|
||||||
self::assertIsString($methodName);
|
|
||||||
$this->assertTrue(method_exists(MenuSubscriber::class, $methodName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -49,7 +49,6 @@ abstract class BaseFormTypeQueryTest extends TestCase
|
|||||||
$team = new Team('foo');
|
$team = new Team('foo');
|
||||||
self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam($team));
|
self::assertInstanceOf(BaseFormTypeQuery::class, $sut->addTeam($team));
|
||||||
self::assertCount(1, $sut->getTeams());
|
self::assertCount(1, $sut->getTeams());
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
self::assertSame($team, $sut->getTeams()[0]);
|
self::assertSame($team, $sut->getTeams()[0]);
|
||||||
|
|
||||||
$sut->setTeams([]);
|
$sut->setTeams([]);
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ class BaseQueryTest extends TestCase
|
|||||||
|
|
||||||
$team = new Team('foo');
|
$team = new Team('foo');
|
||||||
self::assertInstanceOf(BaseQuery::class, $sut->setTeams([$team]));
|
self::assertInstanceOf(BaseQuery::class, $sut->setTeams([$team]));
|
||||||
self::assertEquals(1, \count($sut->getTeams()));
|
self::assertCount(1, $sut->getTeams());
|
||||||
/* @phpstan-ignore-next-line */
|
|
||||||
self::assertSame($team, $sut->getTeams()[0]);
|
self::assertSame($team, $sut->getTeams()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use Twig\TwigFunction;
|
|||||||
*/
|
*/
|
||||||
class RuntimeExtensionsTest extends TestCase
|
class RuntimeExtensionsTest extends TestCase
|
||||||
{
|
{
|
||||||
public function testGetFilters()
|
public function testGetFilters(): void
|
||||||
{
|
{
|
||||||
$expected = ['md2html', 'desc2html', 'comment2html', 'comment1line', 'colorize', 'icon'];
|
$expected = ['md2html', 'desc2html', 'comment2html', 'comment1line', 'colorize', 'icon'];
|
||||||
$i = 0;
|
$i = 0;
|
||||||
@@ -35,7 +35,7 @@ class RuntimeExtensionsTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetFunctions()
|
public function testGetFunctions(): void
|
||||||
{
|
{
|
||||||
$expected = [
|
$expected = [
|
||||||
'trigger',
|
'trigger',
|
||||||
@@ -50,6 +50,7 @@ class RuntimeExtensionsTest extends TestCase
|
|||||||
'render_widget',
|
'render_widget',
|
||||||
'icon',
|
'icon',
|
||||||
'qr_code_data_uri',
|
'qr_code_data_uri',
|
||||||
|
'user_shortcuts',
|
||||||
];
|
];
|
||||||
|
|
||||||
$i = 0;
|
$i = 0;
|
||||||
@@ -65,7 +66,7 @@ class RuntimeExtensionsTest extends TestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testGetFilterDefinition()
|
public function testGetFilterDefinition(): void
|
||||||
{
|
{
|
||||||
$sut = new RuntimeExtensions();
|
$sut = new RuntimeExtensions();
|
||||||
$filters = $sut->getFilters();
|
$filters = $sut->getFilters();
|
||||||
|
|||||||
@@ -8852,21 +8852,6 @@ parameters:
|
|||||||
count: 1
|
count: 1
|
||||||
path: Twig/Runtime/WidgetExtensionTest.php
|
path: Twig/Runtime/WidgetExtensionTest.php
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method App\\\\Tests\\\\Twig\\\\RuntimeExtensionsTest\\:\\:testGetFilterDefinition\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: Twig/RuntimeExtensionsTest.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method App\\\\Tests\\\\Twig\\\\RuntimeExtensionsTest\\:\\:testGetFilters\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: Twig/RuntimeExtensionsTest.php
|
|
||||||
|
|
||||||
-
|
|
||||||
message: "#^Method App\\\\Tests\\\\Twig\\\\RuntimeExtensionsTest\\:\\:testGetFunctions\\(\\) has no return type specified\\.$#"
|
|
||||||
count: 1
|
|
||||||
path: Twig/RuntimeExtensionsTest.php
|
|
||||||
|
|
||||||
-
|
-
|
||||||
message: "#^Method App\\\\Tests\\\\Utils\\\\ColorTest\\:\\:assertIsValidColor\\(\\) has no return type specified\\.$#"
|
message: "#^Method App\\\\Tests\\\\Utils\\\\ColorTest\\:\\:assertIsValidColor\\(\\) has no return type specified\\.$#"
|
||||||
count: 1
|
count: 1
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5G3QNHA" resname="activity.filter">
|
<trans-unit id="5G3QNHA" resname="activity.filter">
|
||||||
<source>Filter activities</source>
|
<source>Filter activities</source>
|
||||||
<target state="translated">Aktivitäten filtern</target>
|
<target state="translated">Tätigkeiten filtern</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="b1pgNOd" resname="copy">
|
<trans-unit id="b1pgNOd" resname="copy">
|
||||||
<source>copy</source>
|
<source>copy</source>
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="UbouFOs" resname="create-activity">
|
<trans-unit id="UbouFOs" resname="create-activity">
|
||||||
<source>create-activity</source>
|
<source>create-activity</source>
|
||||||
<target state="translated">Aktivität erstellen</target>
|
<target state="translated">Tätigkeit erstellen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="QR1nvcR" resname="create-timesheet">
|
<trans-unit id="QR1nvcR" resname="create-timesheet">
|
||||||
<source>create-timesheet</source>
|
<source>create-timesheet</source>
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="BlGGO.X" resname="activity">
|
<trans-unit id="BlGGO.X" resname="activity">
|
||||||
<source>activity</source>
|
<source>activity</source>
|
||||||
<target>Aktivität</target>
|
<target>Tätigkeit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="oRa0mkz" resname="activity_user">
|
<trans-unit id="oRa0mkz" resname="activity_user">
|
||||||
<source>activity_user</source>
|
<source>activity_user</source>
|
||||||
<target>Aktivität und Benutzer</target>
|
<target>Tätigkeit und Benutzer</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="JEIQ5IQ" resname="project">
|
<trans-unit id="JEIQ5IQ" resname="project">
|
||||||
<source>project</source>
|
<source>project</source>
|
||||||
|
|||||||
@@ -24,11 +24,11 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="BlGGO.X" resname="activity">
|
<trans-unit id="BlGGO.X" resname="activity">
|
||||||
<source>activity</source>
|
<source>activity</source>
|
||||||
<target>Aktivität</target>
|
<target>Tätigkeit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="oRa0mkz" resname="activity_user">
|
<trans-unit id="oRa0mkz" resname="activity_user">
|
||||||
<source>activity_user</source>
|
<source>activity_user</source>
|
||||||
<target>Aktivität und Benutzer</target>
|
<target>Tätigkeit und Benutzer</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="JEIQ5IQ" resname="project">
|
<trans-unit id="JEIQ5IQ" resname="project">
|
||||||
<source>project</source>
|
<source>project</source>
|
||||||
|
|||||||
@@ -886,11 +886,11 @@
|
|||||||
<source>profile.registration_date</source>
|
<source>profile.registration_date</source>
|
||||||
<target>Registrován</target>
|
<target>Registrován</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Připojit</target>
|
<target>Připojit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Nahradit</target>
|
<target>Nahradit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -349,11 +349,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Farve</target>
|
<target>Farve</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Erstat</target>
|
<target>Erstat</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Tilføj</target>
|
<target>Tilføj</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -523,11 +523,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Farbe</target>
|
<target>Farbe</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Ersetzen</target>
|
<target>Ersetzen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Hinzufügen</target>
|
<target>Hinzufügen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1573,6 +1573,10 @@
|
|||||||
<source>absence</source>
|
<source>absence</source>
|
||||||
<target>Abwesenheit</target>
|
<target>Abwesenheit</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="YTzKpcP" resname="Absence calendar">
|
||||||
|
<source>Absence calendar</source>
|
||||||
|
<target>Abwesenheitskalender</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4PMHpIp" resname="time_off">
|
<trans-unit id="4PMHpIp" resname="time_off">
|
||||||
<source>time_off</source>
|
<source>time_off</source>
|
||||||
<target>Freizeitausgleich</target>
|
<target>Freizeitausgleich</target>
|
||||||
@@ -1633,6 +1637,42 @@
|
|||||||
<source>force_password_change_help</source>
|
<source>force_password_change_help</source>
|
||||||
<target state="translated">Bei der nächsten Anmeldung muss der Benutzer ein neues Passwort hinterlegen.</target>
|
<target state="translated">Bei der nächsten Anmeldung muss der Benutzer ein neues Passwort hinterlegen.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="vURcRit" resname="overview">
|
||||||
|
<source>Overview</source>
|
||||||
|
<target>Übersicht</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0xFBb6O" resname="Expenses">
|
||||||
|
<source>Expenses</source>
|
||||||
|
<target>Ausgaben</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="KSwG8AR" resname="Category">
|
||||||
|
<source>Category</source>
|
||||||
|
<target>Kategorie</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="uLHYlMa" resname="Categories">
|
||||||
|
<source>Categories</source>
|
||||||
|
<target>Kategorien</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7Sycs4M" resname="Importer">
|
||||||
|
<source>Importer</source>
|
||||||
|
<target>Importer</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="J6EJUj9" resname="Meta fields">
|
||||||
|
<source>Meta fields</source>
|
||||||
|
<target>Eigene Felder</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="JmpBuQ1" resname="Translations">
|
||||||
|
<source>Translations</source>
|
||||||
|
<target>Übersetzungen</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b712axp" resname="Translation">
|
||||||
|
<source>Translation</source>
|
||||||
|
<target>Übersetzung</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="Vp7xjKh" resname="Audit logs">
|
||||||
|
<source>Audit logs</source>
|
||||||
|
<target>Audit-Logs</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -573,11 +573,11 @@
|
|||||||
<source>profile.title</source>
|
<source>profile.title</source>
|
||||||
<target>Benutzerprofil</target>
|
<target>Benutzerprofil</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Hinzufügen</target>
|
<target>Hinzufügen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Ersetzen</target>
|
<target>Ersetzen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -441,11 +441,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Χρώμα</target>
|
<target>Χρώμα</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Αντικατάσταση</target>
|
<target>Αντικατάσταση</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Προσάρτηση</target>
|
<target>Προσάρτηση</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -523,11 +523,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Color</target>
|
<target>Color</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Replace</target>
|
<target>Replace</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Append</target>
|
<target>Append</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1573,6 +1573,10 @@
|
|||||||
<source>absence</source>
|
<source>absence</source>
|
||||||
<target>Absence</target>
|
<target>Absence</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="YTzKpcP" resname="Absence calendar">
|
||||||
|
<source>Absence calendar</source>
|
||||||
|
<target>Absence calendar</target>
|
||||||
|
</trans-unit>
|
||||||
<trans-unit id="4PMHpIp" resname="time_off">
|
<trans-unit id="4PMHpIp" resname="time_off">
|
||||||
<source>time_off</source>
|
<source>time_off</source>
|
||||||
<target>Time off</target>
|
<target>Time off</target>
|
||||||
@@ -1633,6 +1637,42 @@
|
|||||||
<source>force_password_change_help</source>
|
<source>force_password_change_help</source>
|
||||||
<target>The next time the user logs in, they must enter a new password.</target>
|
<target>The next time the user logs in, they must enter a new password.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="vURcRit" resname="overview">
|
||||||
|
<source>Overview</source>
|
||||||
|
<target>Overview</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0xFBb6O" resname="Expenses">
|
||||||
|
<source>Expenses</source>
|
||||||
|
<target>Expenses</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="KSwG8AR" resname="Category">
|
||||||
|
<source>Category</source>
|
||||||
|
<target>Category</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="uLHYlMa" resname="Categories">
|
||||||
|
<source>Categories</source>
|
||||||
|
<target>Categories</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="7Sycs4M" resname="Importer">
|
||||||
|
<source>Importer</source>
|
||||||
|
<target>Importer</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="J6EJUj9" resname="Meta fields">
|
||||||
|
<source>Meta fields</source>
|
||||||
|
<target>Custom fields</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="JmpBuQ1" resname="Translations">
|
||||||
|
<source>Translations</source>
|
||||||
|
<target>Translations</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="b712axp" resname="Translation">
|
||||||
|
<source>Translation</source>
|
||||||
|
<target>Translation</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="Vp7xjKh" resname="Audit logs">
|
||||||
|
<source>Audit logs</source>
|
||||||
|
<target>Audit logs</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -373,11 +373,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Koloro</target>
|
<target>Koloro</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Anstataŭigi</target>
|
<target>Anstataŭigi</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Postglui</target>
|
<target>Postglui</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -910,7 +910,7 @@
|
|||||||
<source>status</source>
|
<source>status</source>
|
||||||
<target>Situación</target>
|
<target>Situación</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Reemplazar</target>
|
<target>Reemplazar</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1654,7 +1654,7 @@
|
|||||||
<source>Account working times</source>
|
<source>Account working times</source>
|
||||||
<target state="translated">Horario de atención al público</target>
|
<target state="translated">Horario de atención al público</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Adjuntar</target>
|
<target state="translated">Adjuntar</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -937,11 +937,11 @@
|
|||||||
<source>profile.registration_date</source>
|
<source>profile.registration_date</source>
|
||||||
<target>Hemen erregistratuta</target>
|
<target>Hemen erregistratuta</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Gehitu</target>
|
<target>Gehitu</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Ordeztu</target>
|
<target>Ordeztu</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -405,11 +405,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target state="translated">Väri</target>
|
<target state="translated">Väri</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">Vaihda</target>
|
<target state="translated">Vaihda</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Lisää</target>
|
<target state="translated">Lisää</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -759,11 +759,11 @@
|
|||||||
<source>profile.title</source>
|
<source>profile.title</source>
|
||||||
<target>Brúkara vangi</target>
|
<target>Brúkara vangi</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Legg aftrat</target>
|
<target>Legg aftrat</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Útskift</target>
|
<target>Útskift</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -766,11 +766,11 @@
|
|||||||
<source>globalsOnly</source>
|
<source>globalsOnly</source>
|
||||||
<target>Uniquement global</target>
|
<target>Uniquement global</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Ajouter</target>
|
<target>Ajouter</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Remplacer</target>
|
<target>Remplacer</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1550,6 +1550,10 @@
|
|||||||
<source>confirmed_by_at</source>
|
<source>confirmed_by_at</source>
|
||||||
<target state="needs-translation">Confirmed by %user% at %date%</target>
|
<target state="needs-translation">Confirmed by %user% at %date%</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="J6EJUj9" resname="Meta fields">
|
||||||
|
<source>Meta fields</source>
|
||||||
|
<target>Champs personnalisés</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -1590,7 +1590,7 @@
|
|||||||
<source>supervisor</source>
|
<source>supervisor</source>
|
||||||
<target state="translated">פיקוח</target>
|
<target state="translated">פיקוח</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">הוספה לסוף</target>
|
<target state="translated">הוספה לסוף</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1598,7 +1598,7 @@
|
|||||||
<source>force_password_change</source>
|
<source>force_password_change</source>
|
||||||
<target state="translated">בקשת סיסמה חדשה</target>
|
<target state="translated">בקשת סיסמה חדשה</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">החלפה</target>
|
<target state="translated">החלפה</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1606,6 +1606,18 @@
|
|||||||
<source>force_password_change_help</source>
|
<source>force_password_change_help</source>
|
||||||
<target state="translated">בכניסה הבאה של המשתמש, צריך למלא סיסמה חדש.</target>
|
<target state="translated">בכניסה הבאה של המשתמש, צריך למלא סיסמה חדש.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="0xFBb6O" resname="Expenses">
|
||||||
|
<source>Expenses</source>
|
||||||
|
<target>הוצאות</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="uLHYlMa" resname="Categories">
|
||||||
|
<source>Categories</source>
|
||||||
|
<target>קטגוריות</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="KSwG8AR" resname="Category">
|
||||||
|
<source>Category</source>
|
||||||
|
<target>קטגוריה</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -453,11 +453,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Boja</target>
|
<target>Boja</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Zamijeni</target>
|
<target>Zamijeni</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Dodaj</target>
|
<target>Dodaj</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -405,11 +405,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Colore</target>
|
<target>Colore</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Sostituisci</target>
|
<target>Sostituisci</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Appendi</target>
|
<target state="translated">Appendi</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -1634,6 +1634,18 @@
|
|||||||
<source>holiday</source>
|
<source>holiday</source>
|
||||||
<target state="translated">Vakantie</target>
|
<target state="translated">Vakantie</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="0xFBb6O" resname="Expenses">
|
||||||
|
<source>Expenses</source>
|
||||||
|
<target>Kosten</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="KSwG8AR" resname="Category">
|
||||||
|
<source>Category</source>
|
||||||
|
<target>Categorie</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="uLHYlMa" resname="Categories">
|
||||||
|
<source>Categories</source>
|
||||||
|
<target>Categorieën</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -361,11 +361,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Kolor</target>
|
<target>Kolor</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Zamień</target>
|
<target>Zamień</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Dodaj</target>
|
<target>Dodaj</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1542,6 +1542,22 @@
|
|||||||
<source>supervisor</source>
|
<source>supervisor</source>
|
||||||
<target state="translated">Kierowca</target>
|
<target state="translated">Kierowca</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="0xFBb6O" resname="Expenses">
|
||||||
|
<source>Expenses</source>
|
||||||
|
<target>Wydatki</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="KSwG8AR" resname="Category">
|
||||||
|
<source>Category</source>
|
||||||
|
<target>Kategorie</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="uLHYlMa" resname="Categories">
|
||||||
|
<source>Categories</source>
|
||||||
|
<target>Categories</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="Vp7xjKh" resname="Audit logs">
|
||||||
|
<source>Audit logs</source>
|
||||||
|
<target>Historia zmian</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -862,11 +862,11 @@
|
|||||||
<source>lastLogin</source>
|
<source>lastLogin</source>
|
||||||
<target>Última sessão</target>
|
<target>Última sessão</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Anexar</target>
|
<target>Anexar</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Substituir</target>
|
<target>Substituir</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -1654,7 +1654,7 @@
|
|||||||
<source>supervisor</source>
|
<source>supervisor</source>
|
||||||
<target state="translated">Supervisor</target>
|
<target state="translated">Supervisor</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Acrescentar</target>
|
<target state="translated">Acrescentar</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1662,7 +1662,7 @@
|
|||||||
<source>force_password_change</source>
|
<source>force_password_change</source>
|
||||||
<target state="translated">Solicitar uma nova senha</target>
|
<target state="translated">Solicitar uma nova senha</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">Substituir</target>
|
<target state="translated">Substituir</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -712,11 +712,11 @@
|
|||||||
<source>profile.registration_date</source>
|
<source>profile.registration_date</source>
|
||||||
<target state="translated">Зарегистрирован(-а)</target>
|
<target state="translated">Зарегистрирован(-а)</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Добавить</target>
|
<target state="translated">Добавить</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">Заменить</target>
|
<target state="translated">Заменить</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -357,11 +357,11 @@
|
|||||||
<source>color</source>
|
<source>color</source>
|
||||||
<target>Farba</target>
|
<target>Farba</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Zmeniť</target>
|
<target>Zmeniť</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Pridať</target>
|
<target>Pridať</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -938,11 +938,11 @@
|
|||||||
<source>export_decimal</source>
|
<source>export_decimal</source>
|
||||||
<target>Använd decimallängd vid export</target>
|
<target>Använd decimallängd vid export</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target>Fäst</target>
|
<target>Fäst</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target>Ersätt</target>
|
<target>Ersätt</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -1654,7 +1654,7 @@
|
|||||||
<source>supervisor</source>
|
<source>supervisor</source>
|
||||||
<target state="translated">Süpervizör</target>
|
<target state="translated">Süpervizör</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Sonuna ekle</target>
|
<target state="translated">Sonuna ekle</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -1662,7 +1662,7 @@
|
|||||||
<source>force_password_change</source>
|
<source>force_password_change</source>
|
||||||
<target state="translated">Yeni parola iste</target>
|
<target state="translated">Yeni parola iste</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">Değiştir</target>
|
<target state="translated">Değiştir</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -1590,11 +1590,11 @@
|
|||||||
<source>supervisor</source>
|
<source>supervisor</source>
|
||||||
<target state="translated">Керівник</target>
|
<target state="translated">Керівник</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ICpl9sx" resname="append">
|
<trans-unit id="rlJLVNm" resname="append">
|
||||||
<source>append</source>
|
<source>append</source>
|
||||||
<target state="translated">Додати</target>
|
<target state="translated">Додати</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="tl01EdS" resname="replace">
|
<trans-unit id="erN3h3b" resname="replace">
|
||||||
<source>replace</source>
|
<source>replace</source>
|
||||||
<target state="translated">Замінити</target>
|
<target state="translated">Замінити</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8RaUHlW" resname="report_customer_monthly_projects">
|
<trans-unit id="8RaUHlW" resname="report_customer_monthly_projects">
|
||||||
<source>report_customer_monthly_projects</source>
|
<source>report_customer_monthly_projects</source>
|
||||||
<target state="translated">Projekte nach Monat, Aktivität und Benutzer</target>
|
<target state="translated">Projekte nach Monat, Tätigkeit und Benutzer</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
|
|||||||
@@ -296,7 +296,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="12sQGSo" resname="activity.allow_inline_create">
|
<trans-unit id="12sQGSo" resname="activity.allow_inline_create">
|
||||||
<source>activity.allow_inline_create</source>
|
<source>activity.allow_inline_create</source>
|
||||||
<target state="translated">Erstellung von Aktivitäten im Zeiterfassungsformular zulassen</target>
|
<target state="translated">Erstellung von Tätigkeiten im Zeiterfassungsformular zulassen</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="pBxkAF_" resname="copy_teams_on_create" approved="no">
|
<trans-unit id="pBxkAF_" resname="copy_teams_on_create" approved="no">
|
||||||
<source>copy_teams_on_create</source>
|
<source>copy_teams_on_create</source>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<trans-unit id="FC4DW27" resname="team.activity_visibility_inherited">
|
<trans-unit id="FC4DW27" resname="team.activity_visibility_inherited">
|
||||||
<source>team.activity_visibility_inherited</source>
|
<source>team.activity_visibility_inherited</source>
|
||||||
<target state="translated">Die Aktivität hat eingeschränkten Zugriff, da Teamberechtigungen für das Projekt und/oder den Kunden festgelegt sind.</target>
|
<target state="translated">Die Tätigkeit hat eingeschränkten Zugriff, da Teamberechtigungen für das Projekt und/oder den Kunden festgelegt sind.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6g81kYY" approved="no" resname="team.member">
|
<trans-unit id="6g81kYY" approved="no" resname="team.member">
|
||||||
<source>team.member</source>
|
<source>team.member</source>
|
||||||
|
|||||||
@@ -106,6 +106,50 @@
|
|||||||
<source>This value is not a valid role name.</source>
|
<source>This value is not a valid role name.</source>
|
||||||
<target>Dies ist kein gültiger Name für eine Benutzer-Rolle.</target>
|
<target>Dies ist kein gültiger Name für eine Benutzer-Rolle.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="ZObikpA" resname="This absence type is not known.">
|
||||||
|
<source>This absence type is not known.</source>
|
||||||
|
<target>Dieser Abwesenheitstyp ist nicht bekannt.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0ULsHQA" resname="The chosen date is not a working day.">
|
||||||
|
<source>The chosen date is not a working day.</source>
|
||||||
|
<target>Das ausgewählte Datum ist kein Arbeitstag.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="N21br.P" resname="The chosen date is already locked.">
|
||||||
|
<source>The chosen date is already locked.</source>
|
||||||
|
<target>Das ausgewählte Datum ist bereits gesperrt.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6H84TMs" resname="An absence must be assigned to a user.">
|
||||||
|
<source>An absence must be assigned to a user.</source>
|
||||||
|
<target>Eine Abwesenheit muss einem Benutzer zugewiesen werden.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="nLcihCc" resname="An absence must have a date.">
|
||||||
|
<source>An absence must have a date.</source>
|
||||||
|
<target>Eine Abwesenheit muss ein Datum haben.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="SZO4xjC" resname="An absence cannot be booked before your first working day.">
|
||||||
|
<source>An absence cannot be booked before your first working day.</source>
|
||||||
|
<target>Eine Abwesenheit kann nicht vor dem ersten Arbeitstag gebucht werden.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="IN37g5N" resname="Not enough holidays left.">
|
||||||
|
<source>Not enough holidays left.</source>
|
||||||
|
<target>Nicht mehr genügend Urlaubstage übrig.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="ByeEMxW" resname="You do not have enough overtime, remaining are {{ value }}.">
|
||||||
|
<source>You do not have enough overtime, remaining are {{ value }}.</source>
|
||||||
|
<target>Sie haben nicht genug Überstunden, es verbleiben {{ Wert }}.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="DiaaRa1" resname="You cannot have two absences of this type at one day.">
|
||||||
|
<source>You cannot have two absences of this type at one day.</source>
|
||||||
|
<target>Sie können nicht zwei Abwesenheiten dieser Art an einem Tag buchen.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="kSBiyaF" resname="This is a public holiday, booking not allowed.">
|
||||||
|
<source>This is a public holiday, booking not allowed.</source>
|
||||||
|
<target>Dies ist ein Feiertag, Buchung ist nicht erlaubt.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
||||||
|
<source>You can book a maximum of {{ value }} days at once.</source>
|
||||||
|
<target>Sie können maximal {{ Wert }} Tage auf einmal buchen.</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -90,7 +90,7 @@
|
|||||||
<source>Validation Failed</source>
|
<source>Validation Failed</source>
|
||||||
<target>There was a problem saving.</target>
|
<target>There was a problem saving.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit resname="Cannot stop running timesheet" id="7HYTefs">
|
<trans-unit id="7HYTefs" resname="Cannot stop running timesheet">
|
||||||
<source>Cannot stop running timesheet</source>
|
<source>Cannot stop running timesheet</source>
|
||||||
<target>You have an active time record which cannot be stopped automatically.</target>
|
<target>You have an active time record which cannot be stopped automatically.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
@@ -106,6 +106,50 @@
|
|||||||
<source>This value is not a valid role name.</source>
|
<source>This value is not a valid role name.</source>
|
||||||
<target>This is not a valid name for a user role.</target>
|
<target>This is not a valid name for a user role.</target>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
|
<trans-unit id="ZObikpA" resname="This absence type is not known.">
|
||||||
|
<source>This absence type is not known.</source>
|
||||||
|
<target>This absence type is not known.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="0ULsHQA" resname="The chosen date is not a working day.">
|
||||||
|
<source>The chosen date is not a working day.</source>
|
||||||
|
<target>The chosen date is not a working day.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="N21br.P" resname="The chosen date is already locked.">
|
||||||
|
<source>The chosen date is already locked.</source>
|
||||||
|
<target>The chosen date is already locked.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="6H84TMs" resname="An absence must be assigned to a user.">
|
||||||
|
<source>An absence must be assigned to a user.</source>
|
||||||
|
<target>An absence must be assigned to a user.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="nLcihCc" resname="An absence must have a date.">
|
||||||
|
<source>An absence must have a date.</source>
|
||||||
|
<target>An absence must have a date.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="SZO4xjC" resname="An absence cannot be booked before your first working day.">
|
||||||
|
<source>An absence cannot be booked before your first working day.</source>
|
||||||
|
<target>An absence cannot be booked before your first working day.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="IN37g5N" resname="Not enough holidays left.">
|
||||||
|
<source>Not enough holidays left.</source>
|
||||||
|
<target>Not enough holidays left.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="ByeEMxW" resname="You do not have enough overtime, remaining are {{ value }}.">
|
||||||
|
<source>You do not have enough overtime, remaining are {{ value }}.</source>
|
||||||
|
<target>You do not have enough overtime, remaining are {{ value }}.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="DiaaRa1" resname="You cannot have two absences of this type at one day.">
|
||||||
|
<source>You cannot have two absences of this type at one day.</source>
|
||||||
|
<target>You cannot have two absences of this type at one day.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="kSBiyaF" resname="This is a public holiday, booking not allowed.">
|
||||||
|
<source>This is a public holiday, booking not allowed.</source>
|
||||||
|
<target>This is a public holiday, booking not allowed.</target>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="c2B6.lW" resname="You can book a maximum of {{ value }} days at once.">
|
||||||
|
<source>You can book a maximum of {{ value }} days at once.</source>
|
||||||
|
<target>You can book a maximum of {{ value }} days at once.</target>
|
||||||
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ Encore
|
|||||||
.enableSingleRuntimeChunk()
|
.enableSingleRuntimeChunk()
|
||||||
.enableVersioning(Encore.isProduction())
|
.enableVersioning(Encore.isProduction())
|
||||||
.enableSourceMaps(!Encore.isProduction())
|
.enableSourceMaps(!Encore.isProduction())
|
||||||
.enableBuildNotifications()
|
|
||||||
|
// disabled as ""webpack-notifier": "^1.13"" id currently only compatible with rosetta
|
||||||
|
//.enableBuildNotifications()
|
||||||
|
|
||||||
.enableSassLoader(function(sassOptions) {}, {
|
.enableSassLoader(function(sassOptions) {}, {
|
||||||
resolveUrlLoader: false
|
resolveUrlLoader: false
|
||||||
|
|||||||
64
yarn.lock
64
yarn.lock
@@ -1397,10 +1397,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@fortawesome/fontawesome-free@npm:^6.2.0":
|
"@fortawesome/fontawesome-free@npm:^6.5.0":
|
||||||
version: 6.2.0
|
version: 6.5.0
|
||||||
resolution: "@fortawesome/fontawesome-free@npm:6.2.0"
|
resolution: "@fortawesome/fontawesome-free@npm:6.5.0"
|
||||||
checksum: fd3fcc0a963b907110922b5ac0ca67633aea20b5034102a1f5d285830f7f7a27f9c9de0c4a30228ccd2579bd8f95581a1bbef9519c7b74632e7012d60dd57bb7
|
checksum: 5bbb2beeb885136f97afcd41444f52502f0db990b5839ee7c795870db8a4aa64e6786b3c7c6913515c16b511ccd406d2d51c5a07474294dd737d51301cf69b0d
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -2892,9 +2892,9 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001359, caniuse-lite@npm:^1.0.30001400":
|
"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001359, caniuse-lite@npm:^1.0.30001400":
|
||||||
version: 1.0.30001520
|
version: 1.0.30001565
|
||||||
resolution: "caniuse-lite@npm:1.0.30001520"
|
resolution: "caniuse-lite@npm:1.0.30001565"
|
||||||
checksum: 59991ad8f36cf282f81abbcc6074c3097c21914cdd54bd2b3f73ac9462f57fc74e90371cd22bcdff4d085d09da42a07dcea384cb81e4ac260496e1bd79e1fe7c
|
checksum: 7621f358d0e1158557430a111ca5506008ae0b2c796039ef53aeebf4e2ba15e5241cb89def21ea3a633b6a609273085835b44a522165d871fa44067cdf29cccd
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -4274,13 +4274,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"growly@npm:^1.3.0":
|
|
||||||
version: 1.3.0
|
|
||||||
resolution: "growly@npm:1.3.0"
|
|
||||||
checksum: 53cdecd4c16d7d9154a9061a9ccb87d602e957502ca69b529d7d1b2436c2c0b700ec544fc6b3e4cd115d59b81e62e44ce86bd0521403b579d3a2a97d7ce72a44
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"handle-thing@npm:^2.0.0":
|
"handle-thing@npm:^2.0.0":
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
resolution: "handle-thing@npm:2.0.1"
|
resolution: "handle-thing@npm:2.0.1"
|
||||||
@@ -4895,7 +4888,7 @@ __metadata:
|
|||||||
"@babel/core": ^7.19.6
|
"@babel/core": ^7.19.6
|
||||||
"@babel/eslint-parser": ^7.18.2
|
"@babel/eslint-parser": ^7.18.2
|
||||||
"@babel/preset-env": ^7.19.4
|
"@babel/preset-env": ^7.19.4
|
||||||
"@fortawesome/fontawesome-free": ^6.2.0
|
"@fortawesome/fontawesome-free": ^6.5.0
|
||||||
"@fullcalendar/bootstrap5": ^5.11
|
"@fullcalendar/bootstrap5": ^5.11
|
||||||
"@fullcalendar/core": ^5.11
|
"@fullcalendar/core": ^5.11
|
||||||
"@fullcalendar/daygrid": ^5.11
|
"@fullcalendar/daygrid": ^5.11
|
||||||
@@ -4917,7 +4910,6 @@ __metadata:
|
|||||||
tom-select: ^2.2
|
tom-select: ^2.2
|
||||||
webpack: ^5.74.0
|
webpack: ^5.74.0
|
||||||
webpack-cli: ^4.10.0
|
webpack-cli: ^4.10.0
|
||||||
webpack-notifier: ^1.13
|
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
@@ -5387,20 +5379,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"node-notifier@npm:^9.0.0":
|
|
||||||
version: 9.0.1
|
|
||||||
resolution: "node-notifier@npm:9.0.1"
|
|
||||||
dependencies:
|
|
||||||
growly: ^1.3.0
|
|
||||||
is-wsl: ^2.2.0
|
|
||||||
semver: ^7.3.2
|
|
||||||
shellwords: ^0.1.1
|
|
||||||
uuid: ^8.3.0
|
|
||||||
which: ^2.0.2
|
|
||||||
checksum: a75623912ec6c3fd7c4e6f1c04586adf716a3610268bdbd5adfeb95dc75a2126c10368d98051530aa0dc6fe8d72791d5033ad6dd2a5f63d009fea30f7292f07e
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"node-releases@npm:^2.0.5":
|
"node-releases@npm:^2.0.5":
|
||||||
version: 2.0.5
|
version: 2.0.5
|
||||||
resolution: "node-releases@npm:2.0.5"
|
resolution: "node-releases@npm:2.0.5"
|
||||||
@@ -6747,13 +6725,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"shellwords@npm:^0.1.1":
|
|
||||||
version: 0.1.1
|
|
||||||
resolution: "shellwords@npm:0.1.1"
|
|
||||||
checksum: 8d73a5e9861f5e5f1068e2cfc39bc0002400fe58558ab5e5fa75630d2c3adf44ca1fac81957609c8320d5533e093802fcafc72904bf1a32b95de3c19a0b1c0d4
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"side-channel@npm:^1.0.4":
|
"side-channel@npm:^1.0.4":
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
resolution: "side-channel@npm:1.0.4"
|
resolution: "side-channel@npm:1.0.4"
|
||||||
@@ -6928,7 +6899,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
|
"strip-ansi@npm:^6.0.1":
|
||||||
version: 6.0.1
|
version: 6.0.1
|
||||||
resolution: "strip-ansi@npm:6.0.1"
|
resolution: "strip-ansi@npm:6.0.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -7328,7 +7299,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"uuid@npm:^8.3.0, uuid@npm:^8.3.2":
|
"uuid@npm:^8.3.2":
|
||||||
version: 8.3.2
|
version: 8.3.2
|
||||||
resolution: "uuid@npm:8.3.2"
|
resolution: "uuid@npm:8.3.2"
|
||||||
bin:
|
bin:
|
||||||
@@ -7465,21 +7436,6 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"webpack-notifier@npm:^1.13":
|
|
||||||
version: 1.15.0
|
|
||||||
resolution: "webpack-notifier@npm:1.15.0"
|
|
||||||
dependencies:
|
|
||||||
node-notifier: ^9.0.0
|
|
||||||
strip-ansi: ^6.0.0
|
|
||||||
peerDependencies:
|
|
||||||
"@types/webpack": ">4.41.31"
|
|
||||||
peerDependenciesMeta:
|
|
||||||
"@types/webpack":
|
|
||||||
optional: true
|
|
||||||
checksum: d6dd514b36000b6fb21feb928b0efa8f004f03d28d94bfc3513295f306bc8e5f132984e60e7995af32685f6b544d1deaad7c421527d8f48db6356bdf40190973
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"webpack-sources@npm:^3.2.3":
|
"webpack-sources@npm:^3.2.3":
|
||||||
version: 3.2.3
|
version: 3.2.3
|
||||||
resolution: "webpack-sources@npm:3.2.3"
|
resolution: "webpack-sources@npm:3.2.3"
|
||||||
|
|||||||
Reference in New Issue
Block a user