Release 2.50 (#5835)
* replace p-0 class with fullsize embed option * bump parsedown package * remove support for file:// urls * fix missing macro in export print template * fix weekly hours with breaks
This commit is contained in:
46
composer.lock
generated
46
composer.lock
generated
@@ -1869,24 +1869,24 @@
|
||||
},
|
||||
{
|
||||
"name": "erusev/parsedown",
|
||||
"version": "1.7.4",
|
||||
"version": "1.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/erusev/parsedown.git",
|
||||
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
|
||||
"reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
|
||||
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
|
||||
"url": "https://api.github.com/repos/erusev/parsedown/zipball/96baaad00f71ba04d76e45b4620f54d3beabd6f7",
|
||||
"reference": "96baaad00f71ba04d76e45b4620f54d3beabd6f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=5.3.0"
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^4.8.35"
|
||||
"phpunit/phpunit": "^7.5|^8.5|^9.6"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -1913,9 +1913,15 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/erusev/parsedown/issues",
|
||||
"source": "https://github.com/erusev/parsedown/tree/1.7.x"
|
||||
"source": "https://github.com/erusev/parsedown/tree/1.8.0"
|
||||
},
|
||||
"time": "2019-12-30T22:54:17+00:00"
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/erusev",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-16T11:41:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "friendsofsymfony/rest-bundle",
|
||||
@@ -11437,16 +11443,16 @@
|
||||
},
|
||||
{
|
||||
"name": "friendsofphp/php-cs-fixer",
|
||||
"version": "v3.94.0",
|
||||
"version": "v3.94.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
|
||||
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4"
|
||||
"reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/883b20fb38c7866de9844ab6d0a205c423bde2d4",
|
||||
"reference": "883b20fb38c7866de9844ab6d0a205c423bde2d4",
|
||||
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/d1a3634e29916367b885250e1fc4dfd5ffe3b091",
|
||||
"reference": "d1a3634e29916367b885250e1fc4dfd5ffe3b091",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11529,7 +11535,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.0"
|
||||
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.94.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -11537,7 +11543,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-11T16:44:33+00:00"
|
||||
"time": "2026-02-18T12:24:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "masterminds/html5",
|
||||
@@ -11829,16 +11835,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-doctrine",
|
||||
"version": "2.0.16",
|
||||
"version": "2.0.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan-doctrine.git",
|
||||
"reference": "f4ff6084a26d91174b3f0b047589af293a893104"
|
||||
"reference": "734ef36c2709b51943f04aacadddb76f239562d3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/f4ff6084a26d91174b3f0b047589af293a893104",
|
||||
"reference": "f4ff6084a26d91174b3f0b047589af293a893104",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan-doctrine/zipball/734ef36c2709b51943f04aacadddb76f239562d3",
|
||||
"reference": "734ef36c2709b51943f04aacadddb76f239562d3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11899,9 +11905,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/phpstan/phpstan-doctrine/issues",
|
||||
"source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.16"
|
||||
"source": "https://github.com/phpstan/phpstan-doctrine/tree/2.0.17"
|
||||
},
|
||||
"time": "2026-02-11T08:54:45+00:00"
|
||||
"time": "2026-02-18T10:21:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-phpunit",
|
||||
|
||||
@@ -3800,11 +3800,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Utils/ParsedownExtension.php
|
||||
|
||||
-
|
||||
message: "#^Property App\\\\Utils\\\\ParsedownExtension\\:\\:\\$safeLinksWhitelist has no type specified\\.$#"
|
||||
count: 1
|
||||
path: src/Utils/ParsedownExtension.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$profile of method App\\\\Utils\\\\ProfileManager\\:\\:getProfile\\(\\) expects string, mixed given\\.$#"
|
||||
count: 1
|
||||
|
||||
@@ -17,11 +17,11 @@ final class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.49.0';
|
||||
public const VERSION = '2.50.0';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 24900;
|
||||
public const VERSION_ID = 25000;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -95,6 +95,7 @@ final class QuickEntryTimesheetType extends AbstractType
|
||||
$duration = $data->getDuration(false);
|
||||
try {
|
||||
if (null !== $duration) {
|
||||
$duration += $data->getBreak();
|
||||
$end = clone $data->getBegin();
|
||||
$end->modify('+ ' . abs($duration) . ' seconds');
|
||||
$data->setEnd($end);
|
||||
|
||||
@@ -21,15 +21,17 @@ class Parsedown extends \Parsedown
|
||||
{
|
||||
$block = parent::blockHeader($Line);
|
||||
|
||||
$text = $block['element']['text'];
|
||||
if (isset($block['element']['handler']['argument'])) {
|
||||
$text = $block['element']['handler']['argument'];
|
||||
|
||||
if (\is_string($text) && $text !== '') {
|
||||
$id = $this->getIDfromText($text);
|
||||
if (\is_string($text) && $text !== '') {
|
||||
$id = $this->getIDfromText($text);
|
||||
|
||||
// add id-attribute
|
||||
$block['element']['attributes'] = [
|
||||
'id' => $id
|
||||
];
|
||||
// add id-attribute
|
||||
$block['element']['attributes'] = [
|
||||
'id' => $id
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $block;
|
||||
|
||||
@@ -44,55 +44,17 @@ final class ParsedownExtension extends Parsedown
|
||||
];
|
||||
|
||||
/**
|
||||
* Overwritten to add support for file:///
|
||||
*/
|
||||
protected $safeLinksWhitelist = [
|
||||
'file:///',
|
||||
'http://',
|
||||
'https://',
|
||||
'ftp://',
|
||||
'ftps://',
|
||||
'mailto:',
|
||||
'data:image/png;base64,',
|
||||
'data:image/gif;base64,',
|
||||
'data:image/jpeg;base64,',
|
||||
'irc:',
|
||||
'ircs:',
|
||||
'git:',
|
||||
'ssh:',
|
||||
'news:',
|
||||
'steam:',
|
||||
];
|
||||
|
||||
/**
|
||||
* Overwritten:
|
||||
* - added support for file:///
|
||||
* - open links in new windows
|
||||
* Overwritten to open links in new windows
|
||||
*/
|
||||
protected function inlineUrl($Excerpt): ?array
|
||||
{
|
||||
if ($this->urlsLinked !== true or !isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') {
|
||||
return null;
|
||||
$block = parent::inlineUrl($Excerpt);
|
||||
|
||||
if (isset($block['element']['attributes']) && \is_array($block['element']['attributes'])) {
|
||||
$block['element']['attributes']['target'] = '_blank';
|
||||
}
|
||||
|
||||
if (preg_match('/\b(https?:[\/]{2}|file:[\/]{3})[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) {
|
||||
$url = $matches[0][0];
|
||||
|
||||
return [
|
||||
'extent' => \strlen($matches[0][0]),
|
||||
'position' => $matches[0][1],
|
||||
'element' => [
|
||||
'name' => 'a',
|
||||
'text' => $url,
|
||||
'attributes' => [
|
||||
'href' => $url,
|
||||
'target' => '_blank'
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
return $block;
|
||||
}
|
||||
|
||||
protected function blockTable($Line, ?array $Block = null) // @phpstan-ignore missingType.return,missingType.iterableValue,missingType.parameter
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
{% set currency = activity.project.customer.currency %}
|
||||
{% endif %}
|
||||
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "customer/actions.html.twig" as customerActions %}
|
||||
{% import "project/actions.html.twig" as projectActions %}
|
||||
@@ -21,7 +21,6 @@
|
||||
{{ widgets.card_tool_button('edit', {'class': 'modal-ajax-form open-edit', 'title': 'edit', 'url': path('admin_activity_edit', {'id': activity.id})}) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
{% if activity.comment is not empty %}
|
||||
<div class="comment p-3">
|
||||
|
||||
@@ -55,8 +55,7 @@
|
||||
{% endif %}
|
||||
|
||||
<div class="col-xs-12 {% if hasTwoColumns %}col-md-8 col-lg-9 col-print-12{% endif %}">
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% block box_body %}
|
||||
<div id="timesheet_calendar"></div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{% block main %}
|
||||
{% set can_edit = is_granted('edit', customer) %}
|
||||
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_attributes %}id="customer_details_box"{% endblock %}
|
||||
{% block box_title %}
|
||||
@@ -16,7 +16,6 @@
|
||||
{{ widgets.card_tool_button('edit', {'class': 'modal-ajax-form open-edit', 'title': 'edit', 'url': path('admin_customer_edit', {'id': customer.id})}) }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
{% if customer.comment is not empty %}
|
||||
<div class="comment p-3">
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
{% set timeBudgetVisible = is_granted('time', entity) %}
|
||||
{% set durationTrans = entity.isMonthlyBudget() ? 'stats.durationMonth' : 'stats.workingTime' %}
|
||||
{% if timeBudgetVisible %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/progressbar.html.twig" as progress %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_title %}
|
||||
{{ 'timeBudget'|trans }} {% if entity.isMonthlyBudget() %}({{ 'budgetType_month'|trans }}){% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_attributes %}id="time_budget_box"{% endblock %}
|
||||
{% block box_body %}
|
||||
<div class="row">
|
||||
@@ -59,13 +58,12 @@
|
||||
{% endembed %}
|
||||
{% endif %}
|
||||
{% if is_granted('budget', entity) %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/progressbar.html.twig" as progress %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_title %}
|
||||
{{ 'budget'|trans }} {% if entity.isMonthlyBudget() %}({{ 'budgetType_month'|trans }}){% endif %}
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_attributes %}id="budget_box"{% endblock %}
|
||||
{% block box_body %}
|
||||
<div class="row">
|
||||
|
||||
@@ -104,13 +104,12 @@
|
||||
{% if entries is empty %}
|
||||
{{ widgets.nothing_found() }}
|
||||
{% else %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_title %}
|
||||
{{ 'preview'|trans }}
|
||||
{% endblock %}
|
||||
{% block box_attributes %}id="preview_export"{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_footer %}
|
||||
{% if showMarkAsExportedButton %}
|
||||
<div class="d-flex">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ app.locale }}">
|
||||
{% from "macros/meta_fields.html.twig" import meta_field_value %}
|
||||
{% from "macros/meta_fields.html.twig" import meta_field_value, form_type_value %}
|
||||
{% set storageItemName = 'kimai_html_export' %}
|
||||
{% set decimal = decimal|default(false) %}
|
||||
{% set columnTitles = {} %}
|
||||
@@ -507,7 +507,7 @@
|
||||
<td class="column-{{ 'u_' ~ field.name }} text-nowrap" {% if not columns['u_' ~ field.name] %}style="display: none"{% endif %}>
|
||||
{% set metaField = entry.user.preference(field.name) %}
|
||||
{% if not metaField is null and metaField.value is not null and metaField.value is not empty %}
|
||||
{{ _self.form_type_value(field.type, metaField.value, entry.user) }}
|
||||
{{ form_type_value(field.type, metaField.value, entry.user) }}
|
||||
{% endif %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
|
||||
@@ -35,14 +35,13 @@
|
||||
{% endif %}
|
||||
|
||||
{% if documents|length > 0 %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {'documents': documents} %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {'documents': documents, fullsize: true} %}
|
||||
{% import "invoice/actions.html.twig" as actions %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% block box_title %}{{ 'invoice_renderer'|trans({}, 'invoice-renderer') }}{% endblock %}
|
||||
{% block box_attributes %}
|
||||
id="invoice_document_list"
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
<table class="table table-hover dataTable">
|
||||
<thead>
|
||||
|
||||
@@ -90,14 +90,13 @@
|
||||
{% endif %}
|
||||
|
||||
{% if models|length > 0 %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "macros/datatables.html.twig" as tables %}
|
||||
{% block box_title %}
|
||||
{{ 'preview'|trans }}
|
||||
{% endblock %}
|
||||
{% block box_attributes %}id="invoice_customer_forms"{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
<table class="table dataTable">
|
||||
<thead>
|
||||
|
||||
@@ -3,40 +3,42 @@
|
||||
{% set metaField = entity.metaField(field.name) %}
|
||||
{% if not metaField is null %}
|
||||
{% set metaField = metaField.merge(field) %}
|
||||
{% set type = metaField.type %}
|
||||
{% set value = metaField.value %}
|
||||
{% if 'DurationType' in type %}
|
||||
{{ value|duration }}
|
||||
{% elseif 'YesNoType' in type or 'CheckboxType' in type %}
|
||||
{{ value ? ('yes'|trans) : ('no'|trans) }}
|
||||
{% elseif 'DatePickerType' in type %}
|
||||
{{ value|date_short }}
|
||||
{% elseif 'DateTimePickerType' in type %}
|
||||
{{ value|date_time }}
|
||||
{% elseif 'CountryType' in type %}
|
||||
{{ value|country_name }}
|
||||
{% elseif 'CurrencyType' in type %}
|
||||
{{ value|currency_name }}
|
||||
{% elseif 'LanguageType' in type %}
|
||||
{{ value|locale_name }}
|
||||
{% elseif 'MoneyType' in type %}
|
||||
{% set classname = class_name(entity) %}
|
||||
{% if classname == 'App\\Entity\\Timesheet' %}
|
||||
{{ value|money(entity.project.customer.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Customer' %}
|
||||
{{ value|money(entity.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Project' %}
|
||||
{{ value|money(entity.customer.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Activity' and entity.project is not null %}
|
||||
{{ value|money(entity.project.customer.currency) }}
|
||||
{% else %}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
{% elseif 'TextareaType' in type %}
|
||||
{{ value|nl2br }}
|
||||
{% else %}
|
||||
{# EmailType, UrlType, TagsType, ColorPickerType, ColorChoiceType #}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
{{ _self.form_type_value(metaField.type, metaField.value, entity) }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% macro form_type_value(type, value, entity) %}
|
||||
{% if 'DurationType' in type %}
|
||||
{{ value|duration }}
|
||||
{% elseif 'YesNoType' in type or 'CheckboxType' in type %}
|
||||
{{ value ? ('yes'|trans) : ('no'|trans) }}
|
||||
{% elseif 'DatePickerType' in type %}
|
||||
{{ value|date_short }}
|
||||
{% elseif 'DateTimePickerType' in type %}
|
||||
{{ value|date_time }}
|
||||
{% elseif 'CountryType' in type %}
|
||||
{{ value|country_name }}
|
||||
{% elseif 'CurrencyType' in type %}
|
||||
{{ value|currency_name }}
|
||||
{% elseif 'LanguageType' in type %}
|
||||
{{ value|locale_name }}
|
||||
{% elseif 'MoneyType' in type %}
|
||||
{% set classname = class_name(entity) %}
|
||||
{% if classname == 'App\\Entity\\Timesheet' %}
|
||||
{{ value|money(entity.project.customer.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Customer' %}
|
||||
{{ value|money(entity.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Project' %}
|
||||
{{ value|money(entity.customer.currency) }}
|
||||
{% elseif classname == 'App\\Entity\\Activity' and entity.project is not null %}
|
||||
{{ value|money(entity.project.customer.currency) }}
|
||||
{% else %}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
{% elseif 'TextareaType' in type %}
|
||||
{{ value|nl2br }}
|
||||
{% else %}
|
||||
{# EmailType, UrlType, TagsType, ColorPickerType, ColorChoiceType #}
|
||||
{{ value }}
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
{% if plugins|length == 0 %}
|
||||
{{ widgets.callout('warning', 'plugin.none_installed'|trans({}, 'plugins')) }}
|
||||
{% else %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% block box_title %}{{ 'plugin.installed'|trans }}{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
{% set columns = {
|
||||
'name': {'class': 'alwaysVisible w-25'},
|
||||
@@ -46,10 +45,9 @@
|
||||
{% endif %}
|
||||
|
||||
{% if extensions|length > 0 %}
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% from "macros/widgets.html.twig" import card_tool_button %}
|
||||
{% block box_title %}{{ 'plugin.marketplace'|trans({}, 'plugins') }}{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_tools %}
|
||||
{{ card_tool_button('shop', {'title': 'shop', 'translation_domain': 'plugins', 'target': '_blank', 'url': constant('App\\Constants::HOMEPAGE') ~ '/store/', 'icon': false, 'class': 'btn-primary'}) }}
|
||||
{% endblock %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
{% block main %}
|
||||
{% set can_edit = is_granted('edit', project) %}
|
||||
|
||||
{% embed '@theme/embeds/card.html.twig' %}
|
||||
{% embed '@theme/embeds/card.html.twig' with {fullsize: true} %}
|
||||
{% import "macros/widgets.html.twig" as widgets %}
|
||||
{% import "customer/actions.html.twig" as customerActions %}
|
||||
{% block box_attributes %}id="project_details_box"{% endblock %}
|
||||
@@ -16,7 +16,6 @@
|
||||
{% block box_title %}
|
||||
{{ widgets.label_dot(project.name, project.color) }}
|
||||
{% endblock %}
|
||||
{% block box_body_class %}p-0{% endblock %}
|
||||
{% block box_body %}
|
||||
{% if project.comment is not empty %}
|
||||
<div class="comment p-3">
|
||||
|
||||
@@ -15,13 +15,17 @@ use App\Form\Type\QuickEntryTimesheetType;
|
||||
use PHPUnit\Framework\Attributes\CoversClass;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Symfony\Bundle\SecurityBundle\Security;
|
||||
use Symfony\Component\Form\FormExtensionInterface;
|
||||
use Symfony\Component\Form\PreloadedExtension;
|
||||
use Symfony\Component\Form\Test\TypeTestCase;
|
||||
|
||||
#[CoversClass(QuickEntryTimesheetType::class)]
|
||||
class QuickEntryTimesheetTypeTest extends TypeTestCase
|
||||
{
|
||||
protected function getExtensions()
|
||||
/**
|
||||
* @return FormExtensionInterface[]
|
||||
*/
|
||||
protected function getExtensions(): array
|
||||
{
|
||||
$auth = $this->createMock(Security::class);
|
||||
$auth->method('getUser')->willReturn(new User());
|
||||
@@ -36,18 +40,19 @@ class QuickEntryTimesheetTypeTest extends TypeTestCase
|
||||
|
||||
public static function getTestData()
|
||||
{
|
||||
yield [4.5, 16200];
|
||||
yield ['4,5', 16200];
|
||||
yield ['4:30', 16200];
|
||||
yield ['4h30m', 16200];
|
||||
yield [4.5, 0, 16200];
|
||||
yield ['4,5', 0, 16200];
|
||||
yield ['4:30', 0, 16200];
|
||||
yield ['4h30m', 0, 16200];
|
||||
yield ['4h30m', 1800, 16200]; // it is important, that the duration does not change with breaks
|
||||
}
|
||||
|
||||
#[DataProvider('getTestData')]
|
||||
public function testSubmitValidData($value, $expectedDuration): void
|
||||
public function testSubmitValidData(string|float $value, int $break, int $expectedDuration): void
|
||||
{
|
||||
$data = ['duration' => $value];
|
||||
|
||||
$model = $this->createDefaultModel();
|
||||
$model = $this->createDefaultModel($expectedDuration, $break);
|
||||
|
||||
$form = $this->factory->create(QuickEntryTimesheetType::class, $model);
|
||||
|
||||
@@ -56,16 +61,19 @@ class QuickEntryTimesheetTypeTest extends TypeTestCase
|
||||
self::assertTrue($form->isSynchronized());
|
||||
self::assertEquals($expectedDuration, $model->getDuration());
|
||||
self::assertEquals($expectedDuration, $model->getDuration(true));
|
||||
self::assertEquals($break, $model->getBreak());
|
||||
}
|
||||
|
||||
private function createDefaultModel(): Timesheet
|
||||
private function createDefaultModel(int $duration = 0, int $break = 0): Timesheet
|
||||
{
|
||||
$begin = new \DateTime('2020-02-15 12:30:00');
|
||||
$end = new \DateTime('2020-02-15 14:00:00');
|
||||
|
||||
$model = new Timesheet();
|
||||
$model->setBegin($begin);
|
||||
//$model->setDuration($duration);
|
||||
$model->setEnd($end);
|
||||
$model->setBreak($break);
|
||||
|
||||
return $model;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class MarkdownTest extends TestCase
|
||||
asdfasdfa</p>
|
||||
<pre><code>ssdfsdf</code></pre>
|
||||
<p><a href="http://example.com/foo-bar.html" target="_blank">http://example.com/foo-bar.html</a><br />
|
||||
<a href="file:///home/kimai/images/beautiful-flower.png" target="_blank">file:///home/kimai/images/beautiful-flower.png</a></p>
|
||||
file:///home/kimai/images/beautiful-flower.png</p>
|
||||
<p>sdfsdf <a href="#test-1">asdfasdf</a> asdfasdf</p>
|
||||
<p># test<br />
|
||||
aasdfasdf<br />
|
||||
|
||||
@@ -21,7 +21,7 @@ class ParsedownExtensionTest extends TestCase
|
||||
public function testTableContainsCssClasses(): void
|
||||
{
|
||||
$sut = new ParsedownExtension();
|
||||
$html = $sut->parse('
|
||||
$html = $sut->text('
|
||||
| Item | Price |
|
||||
|---|---|
|
||||
| Something | $ 472,78 |
|
||||
@@ -34,7 +34,7 @@ class ParsedownExtensionTest extends TestCase
|
||||
public function testHeaderIsNotConverted(): void
|
||||
{
|
||||
$sut = new ParsedownExtension();
|
||||
$html = $sut->parse('
|
||||
$html = $sut->text('
|
||||
# Foo
|
||||
');
|
||||
self::assertEquals('<p># Foo</p>', $html);
|
||||
|
||||
@@ -19,7 +19,7 @@ class ParsedownTest extends TestCase
|
||||
public function testTableContainsCssClasses(): void
|
||||
{
|
||||
$sut = new Parsedown();
|
||||
$html = $sut->parse('
|
||||
$html = $sut->text('
|
||||
| Item | Price |
|
||||
|---|---|
|
||||
| Something | $ 472,78 |
|
||||
@@ -32,7 +32,7 @@ class ParsedownTest extends TestCase
|
||||
public function testHeaderContainsId(): void
|
||||
{
|
||||
$sut = new Parsedown();
|
||||
$html = $sut->parse('
|
||||
$html = $sut->text('
|
||||
# Foo
|
||||
');
|
||||
self::assertEquals('<h1 id="foo">Foo</h1>', $html);
|
||||
@@ -41,7 +41,7 @@ class ParsedownTest extends TestCase
|
||||
public function testHeaderContainsIdDoesNotDuplicate(): void
|
||||
{
|
||||
$sut = new Parsedown();
|
||||
$html = $sut->parse('
|
||||
$html = $sut->text('
|
||||
# Foo
|
||||
# Foo
|
||||
# Foo
|
||||
|
||||
@@ -1346,26 +1346,11 @@ parameters:
|
||||
count: 1
|
||||
path: Form/Type/DurationTypeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:getExtensions\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Form/Type/QuickEntryTimesheetTypeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:getTestData\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
path: Form/Type/QuickEntryTimesheetTypeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:testSubmitValidData\\(\\) has parameter \\$expectedDuration with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Form/Type/QuickEntryTimesheetTypeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Form\\\\Type\\\\QuickEntryTimesheetTypeTest\\:\\:testSubmitValidData\\(\\) has parameter \\$value with no type specified\\.$#"
|
||||
count: 1
|
||||
path: Form/Type/QuickEntryTimesheetTypeTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Invoice\\\\Calculator\\\\AbstractCalculatorTestCase\\:\\:assertDescription\\(\\) has parameter \\$addActivity with no type specified\\.$#"
|
||||
count: 1
|
||||
|
||||
Reference in New Issue
Block a user