Release 2.11 (#4580)
This commit is contained in:
@@ -64,7 +64,7 @@ final class TranslationCommand extends Command
|
||||
|
||||
$bases = [
|
||||
'core' => $this->projectDirectory . '/translations/*.xlf',
|
||||
//'plugins' => $this->projectDirectory . Kernel::PLUGIN_DIRECTORY . '/*/Resources/translations/*.xlf',
|
||||
'plugins' => $this->projectDirectory . Kernel::PLUGIN_DIRECTORY . '/*/Resources/translations/*.xlf',
|
||||
'theme' => $this->projectDirectory . '/vendor/kevinpapst/tabler-bundle/translations/*.xlf',
|
||||
];
|
||||
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.10.0';
|
||||
public const VERSION = '2.11.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 21000;
|
||||
public const VERSION_ID = 21100;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -26,6 +26,7 @@ use App\Repository\TimesheetRepository;
|
||||
use App\Repository\UserRepository;
|
||||
use App\Timesheet\TimesheetStatisticService;
|
||||
use App\User\UserService;
|
||||
use App\Utils\PageSetup;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use Endroid\QrCode\Builder\Builder;
|
||||
use Endroid\QrCode\Encoding\Encoding;
|
||||
@@ -54,6 +55,17 @@ final class ProfileController extends AbstractController
|
||||
return $this->redirectToRoute('user_profile', ['username' => $this->getUser()->getUserIdentifier()]);
|
||||
}
|
||||
|
||||
private function getPageSetup(User $profile, string $view): PageSetup
|
||||
{
|
||||
$page = new PageSetup('users');
|
||||
$page->setHelp('users.html');
|
||||
$page->setActionName('user');
|
||||
$page->setActionView($view);
|
||||
$page->setActionPayload(['user' => $profile]);
|
||||
|
||||
return $page;
|
||||
}
|
||||
|
||||
#[Route(path: '/{username}', name: 'user_profile', methods: ['GET'])]
|
||||
#[IsGranted('view', 'profile')]
|
||||
public function indexAction(User $profile, TimesheetRepository $repository, TimesheetStatisticService $statisticService): Response
|
||||
@@ -74,6 +86,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
$viewVars = [
|
||||
'tab' => 'charts',
|
||||
'page_setup' => $this->getPageSetup($profile, 'charts'),
|
||||
'user' => $profile,
|
||||
'stats' => $userStats,
|
||||
'workingSince' => $workStartingDay,
|
||||
@@ -105,6 +118,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/profile.html.twig', [
|
||||
'tab' => 'edit',
|
||||
'page_setup' => $this->getPageSetup($profile, 'edit'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -128,6 +142,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/form.html.twig', [
|
||||
'tab' => 'password',
|
||||
'page_setup' => $this->getPageSetup($profile, 'password'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -151,6 +166,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/api-token.html.twig', [
|
||||
'tab' => 'api-token',
|
||||
'page_setup' => $this->getPageSetup($profile, 'api-token'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -182,6 +198,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/form.html.twig', [
|
||||
'tab' => 'roles',
|
||||
'page_setup' => $this->getPageSetup($profile, 'roles'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -208,6 +225,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/contract.html.twig', [
|
||||
'tab' => 'contract',
|
||||
'page_setup' => $this->getPageSetup($profile, 'contract'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -243,6 +261,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/form.html.twig', [
|
||||
'tab' => 'teams',
|
||||
'page_setup' => $this->getPageSetup($profile, 'teams'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
]);
|
||||
@@ -294,6 +313,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/preferences.html.twig', [
|
||||
'tab' => 'settings',
|
||||
'page_setup' => $this->getPageSetup($profile, 'settings'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
'sections' => $sections
|
||||
@@ -422,6 +442,7 @@ final class ProfileController extends AbstractController
|
||||
|
||||
return $this->render('user/2fa.html.twig', [
|
||||
'tab' => '2fa',
|
||||
'page_setup' => $this->getPageSetup($profile, '2fa'),
|
||||
'user' => $profile,
|
||||
'form' => $form->createView(),
|
||||
'deactivate' => $this->getTwoFactorDeactivationForm($profile)->createView(),
|
||||
|
||||
@@ -54,7 +54,7 @@ class Activity implements EntityWithMetaFields, EntityWithBudget
|
||||
*/
|
||||
#[ORM\Column(name: 'name', type: 'string', length: 150, nullable: false)]
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(min: 3, max: 150)]
|
||||
#[Assert\Length(min: 2, max: 150)]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
#[Exporter\Expose(label: 'name')]
|
||||
|
||||
@@ -41,7 +41,7 @@ class Customer implements EntityWithMetaFields, EntityWithBudget
|
||||
private ?int $id = null;
|
||||
#[ORM\Column(name: 'name', type: 'string', length: 150, nullable: false)]
|
||||
#[Assert\NotBlank]
|
||||
#[Assert\Length(min: 3, max: 150)]
|
||||
#[Assert\Length(min: 2, max: 150)]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
#[Exporter\Expose(label: 'name')]
|
||||
|
||||
@@ -59,7 +59,7 @@ class Project implements EntityWithMetaFields, EntityWithBudget
|
||||
*/
|
||||
#[ORM\Column(name: 'name', type: 'string', length: 150, nullable: false)]
|
||||
#[Assert\NotNull]
|
||||
#[Assert\Length(min: 3, max: 150)]
|
||||
#[Assert\Length(min: 2, max: 150)]
|
||||
#[Serializer\Expose]
|
||||
#[Serializer\Groups(['Default'])]
|
||||
#[Exporter\Expose(label: 'name')]
|
||||
|
||||
@@ -19,10 +19,6 @@ use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
/**
|
||||
* When visiting the homepage, this listener redirects the user to the most
|
||||
* appropriate localized version according to the browser settings.
|
||||
*
|
||||
* See http://symfony.com/doc/current/components/http_kernel/introduction.html#the-kernel-request-event
|
||||
*
|
||||
* @author Oleg Voronkovich <oleg-voronkovich@yandex.ru>
|
||||
*/
|
||||
final class RedirectToLocaleSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
@@ -41,7 +37,7 @@ final class RedirectToLocaleSubscriber implements EventSubscriberInterface
|
||||
{
|
||||
$request = $event->getRequest();
|
||||
|
||||
// Ignore sub-requests and all URLs but the homepage
|
||||
// only trigger on the homepage
|
||||
if ('/' !== $request->getPathInfo()) {
|
||||
return;
|
||||
}
|
||||
@@ -53,7 +49,7 @@ final class RedirectToLocaleSubscriber implements EventSubscriberInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$allLanguages = $this->localeService->getAllLocales();
|
||||
$allLanguages = $this->localeService->getTranslatedLocales();
|
||||
|
||||
// Add the default locale at the first position of the array, because getPreferredLanguage()
|
||||
// returns the first element when no appropriate language is found
|
||||
|
||||
@@ -16,10 +16,17 @@ use Symfony\Component\Form\Exception\TransformationFailedException;
|
||||
|
||||
final class TagArrayToStringTransformer implements DataTransformerInterface
|
||||
{
|
||||
private bool $create = true;
|
||||
|
||||
public function __construct(private TagRepository $tagRepository)
|
||||
{
|
||||
}
|
||||
|
||||
public function setCreate(bool $create): void
|
||||
{
|
||||
$this->create = $create;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an array of tags to a string.
|
||||
*
|
||||
@@ -55,15 +62,17 @@ final class TagArrayToStringTransformer implements DataTransformerInterface
|
||||
|
||||
// get the current tags and find the new ones that should be created
|
||||
$tags = $this->tagRepository->findBy(['name' => $names]);
|
||||
// works, because of the implicit case: (string) $tag
|
||||
$newNames = array_diff($names, $tags);
|
||||
if ($this->create) {
|
||||
// works, because of the implicit case: (string) $tag
|
||||
$newNames = array_diff($names, $tags);
|
||||
|
||||
foreach ($newNames as $name) {
|
||||
$tag = new Tag();
|
||||
$tag->setName(mb_substr($name, 0, 100));
|
||||
$tags[] = $tag;
|
||||
foreach ($newNames as $name) {
|
||||
$tag = new Tag();
|
||||
$tag->setName(mb_substr($name, 0, 100));
|
||||
$tags[] = $tag;
|
||||
|
||||
// new tags persist automatically thanks to the cascade={"persist"}
|
||||
// new tags persist automatically thanks to the cascade={"persist"}
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
|
||||
@@ -36,7 +36,7 @@ final class SearchTermType extends AbstractType
|
||||
'placeholder' => 'search',
|
||||
],
|
||||
'constraints' => [
|
||||
new Length(['min' => 3])
|
||||
new Length(['min' => 2])
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -30,9 +30,12 @@ final class TagsInputType extends AbstractType
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->addModelTransformer(new CollectionToArrayTransformer(), true)
|
||||
->addModelTransformer($this->transformer, true);
|
||||
if ($options['allow_create'] === false) {
|
||||
$this->transformer->setCreate(false);
|
||||
}
|
||||
|
||||
$builder->addModelTransformer(new CollectionToArrayTransformer(), true);
|
||||
$builder->addModelTransformer($this->transformer, true);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
|
||||
@@ -16,11 +16,11 @@ use Twig\Extension\RuntimeExtensionInterface;
|
||||
|
||||
final class EncoreExtension implements RuntimeExtensionInterface, ServiceSubscriberInterface
|
||||
{
|
||||
private string $publicDir;
|
||||
|
||||
public function __construct(private ContainerInterface $container, string $projectDirectory)
|
||||
public function __construct(
|
||||
private readonly ContainerInterface $container,
|
||||
private readonly string $projectDirectory
|
||||
)
|
||||
{
|
||||
$this->publicDir = $projectDirectory . '/public';
|
||||
}
|
||||
|
||||
public static function getSubscribedServices(): array
|
||||
@@ -38,7 +38,7 @@ final class EncoreExtension implements RuntimeExtensionInterface, ServiceSubscri
|
||||
$source = '';
|
||||
|
||||
foreach ($files as $file) {
|
||||
$source .= file_get_contents($this->publicDir . '/' . $file);
|
||||
$source .= file_get_contents($this->projectDirectory . '/public/' . $file);
|
||||
}
|
||||
|
||||
$lookup->reset();
|
||||
|
||||
Reference in New Issue
Block a user