added project detail report (#2651)

- avatars via css only
- random colors for entities
- improves print view
- added colors for teams
- added color to tag
This commit is contained in:
Kevin Papst
2021-07-06 22:01:20 +02:00
committed by GitHub
parent cc6031bfde
commit 9ddb87a6fd
122 changed files with 2736 additions and 1549 deletions

View File

@@ -1,59 +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\Twig;
use App\Entity\User;
use App\Utils\AvatarService;
use Symfony\Component\Asset\Packages;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
class AvatarExtension extends AbstractExtension
{
/**
* @var AvatarService
*/
private $avatar;
/**
* @var Packages
*/
private $packages;
public function __construct(AvatarService $avatar, Packages $packages)
{
$this->avatar = $avatar;
$this->packages = $packages;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new TwigFunction('avatar', [$this, 'getAvatarUrl']),
];
}
public function getAvatarUrl(?User $profile, string $default): string
{
if (null === $profile) {
return $this->packages->getUrl($default);
}
$url = $this->avatar->getAvatar($profile);
if (null === $url) {
return $this->packages->getUrl($default);
}
return $this->packages->getUrl($url, 'avatars');
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Kimai time-tracking app.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace App\Twig;
use App\Configuration\SystemConfiguration;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
final class Configuration extends AbstractExtension
{
private $configuration;
private $cache = [];
public function __construct(SystemConfiguration $configuration)
{
$this->configuration = $configuration;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return [
new TwigFunction('config', [$this, 'get']),
];
}
public function get(string $name)
{
if (\array_key_exists($name, $this->cache)) {
return $this->cache[$name];
}
$value = $this->configuration->find($name);
$this->cache[$name] = $value;
return $value;
}
public function __call($name, $arguments)
{
if (\array_key_exists($name, $this->cache)) {
return $this->cache[$name];
}
$checks = ['is' . $name, 'get' . $name, 'has' . $name, $name];
foreach ($checks as $methodName) {
if (method_exists($this->configuration, $methodName)) {
$value = \call_user_func([$this->configuration, $methodName], $arguments);
$this->cache[$name] = $value;
return $value;
}
}
return $this->configuration->find($name);
}
}

View File

@@ -31,6 +31,7 @@ class Extensions extends AbstractExtension
new TwigFilter('multiline_indent', [$this, 'multilineIndent']),
new TwigFilter('color', [$this, 'color']),
new TwigFilter('font_contrast', [$this, 'calculateFontContrastColor']),
new TwigFilter('default_color', [$this, 'defaultColor']),
new TwigFilter('nl2str', [$this, 'replaceNewline'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
];
}
@@ -43,6 +44,7 @@ class Extensions extends AbstractExtension
return [
new TwigFunction('class_name', [$this, 'getClassName']),
new TwigFunction('iso_day_by_name', [$this, 'getIsoDayByName']),
new TwigFunction('random_color', [$this, 'randomColor']),
];
}
@@ -71,11 +73,21 @@ class Extensions extends AbstractExtension
return (new Color())->getColor($entity, $defaultColor);
}
public function randomColor(?string $input = null): string
{
return (new Color())->getRandom($input);
}
public function calculateFontContrastColor(string $color): string
{
return (new Color())->getFontContrastColor($color);
}
public function defaultColor(?string $color = null): string
{
return $color ?? Constants::DEFAULT_COLOR;
}
/**
* @param object $object
* @return null|string

View File

@@ -59,6 +59,7 @@ final class LocaleFormatExtensions extends AbstractExtension
new TwigFilter('time', [$this, 'time']),
new TwigFilter('hour24', [$this, 'hour24']),
new TwigFilter('duration', [$this, 'duration']),
new TwigFilter('chart_duration', [$this, 'durationChart']),
new TwigFilter('duration_decimal', [$this, 'durationDecimal']),
new TwigFilter('money', [$this, 'money']),
new TwigFilter('currency', [$this, 'currency']),
@@ -91,6 +92,7 @@ final class LocaleFormatExtensions extends AbstractExtension
new TwigFunction('get_format_duration', [$this, 'getDurationFormat']),
new TwigFunction('create_date', [$this, 'createDate']),
new TwigFunction('locales', [$this, 'getLocales']),
new TwigFunction('month_names', [$this, 'getMonthNames']),
];
}
@@ -187,6 +189,25 @@ final class LocaleFormatExtensions extends AbstractExtension
return $this->getFormatter()->time($date);
}
/**
* @param string|null $year
* @return string[]
*/
public function getMonthNames(?string $year = null): array
{
$withYear = true;
if ($year === null) {
$year = date('Y');
$withYear = false;
}
$months = [];
for ($i = 1; $i < 13; $i++) {
$months[] = $this->getFormatter()->monthName(new DateTime(sprintf('%s-%s-10', $year, ($i < 10 ? '0' . $i : (string) $i))), $withYear);
}
return $months;
}
public function monthName(\DateTime $dateTime, bool $withYear = false): string
{
return $this->getFormatter()->monthName($dateTime, $withYear);
@@ -235,6 +256,11 @@ final class LocaleFormatExtensions extends AbstractExtension
return $this->getFormatter()->durationDecimal($duration);
}
public function durationChart($duration): string
{
return number_format(($duration / 3600), 2, '.', '');
}
/**
* @param string|float $amount
* @return bool|false|string

View File

@@ -15,6 +15,7 @@ use App\Entity\User;
use App\Event\PageActionsEvent;
use App\Event\ThemeEvent;
use App\Event\ThemeJavascriptTranslationsEvent;
use App\Utils\Color;
use Symfony\Bridge\Twig\AppVariable;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
@@ -26,6 +27,10 @@ final class ThemeExtension implements RuntimeExtensionInterface
private $eventDispatcher;
private $translator;
private $configuration;
/**
* @var bool
*/
private $randomColors;
public function __construct(EventDispatcherInterface $dispatcher, TranslatorInterface $translator, SystemConfiguration $configuration)
{
@@ -135,4 +140,25 @@ final class ThemeExtension implements RuntimeExtensionInterface
return $this->configuration->find($name);
}
public function colorize(?string $color, ?string $identifier = null, ?string $fallback = null): string
{
if ($color !== null) {
return $color;
}
if ($this->randomColors === null) {
$this->randomColors = $this->configuration->isThemeRandomColors();
}
if ($this->randomColors) {
return (new Color())->getRandom($identifier);
}
if ($fallback !== null) {
return $fallback;
}
return Constants::DEFAULT_COLOR;
}
}

View File

@@ -48,6 +48,7 @@ class RuntimeExtensions extends AbstractExtension
new TwigFilter('desc2html', [MarkdownExtension::class, 'timesheetContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment2html', [MarkdownExtension::class, 'commentContent'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('comment1line', [MarkdownExtension::class, 'commentOneLiner'], ['pre_escape' => 'html', 'is_safe' => ['html']]),
new TwigFilter('colorize', [ThemeExtension::class, 'colorize']),
];
}
}