Release 2.48 (#5789)

This commit is contained in:
Kevin Papst
2026-01-30 16:44:26 +01:00
committed by GitHub
parent 3925eacf9f
commit 4a31411d69
114 changed files with 1246 additions and 1224 deletions

View File

@@ -158,28 +158,35 @@
</td>
{% set dayCount = 0 %}
{% for day in month.days %}
{% set class = 'text-end contractDay text-nowrap' %}
{% if day.workingTime.expectedTime == 0 %}
{% set class = class ~ ' weekend' %}
{% endif %}
{% set style = null %}
{% if day.workingTime.expectedTime > 0 and day.workingTime.actualTime == 0 and now > day.day %}
{% set class = class ~ ' bg-orange-lt' %}
{% set style = 'missing' %}
{% elseif day.workingTime.expectedTime == 0 and day.workingTime.actualTime > 0 and now > day.day %}
{% set class = class ~ ' bg-yellow-lt' %}
{% set style = 'unexpected' %}
{% endif %}
<td class="{{ class }}">
{% if (day.workingTime.expectedTime != 0 or day.workingTime.actualTime != 0) and (now > day.day or day.workingTime.actualTime > 0) %}
{% if day.hasAddons() %}
{% set statusTitle = '' %}
{% for addon in day.getAddons() %}
{% set statusTitle = statusTitle ~ (addon.title|trans) ~ ' (' ~ addon.visibleDuration|duration(decimal) ~ ')' %}
{% if not loop.last %}
{% set statusTitle = statusTitle ~ ', ' %}
{% endif %}
{% endfor %}
<span class="status-dot status-azure" data-toggle="tooltip" data-placement="top" title="{{ statusTitle }}"></span>
{% set statusTitle = null %}
{% if day.hasAddons() %}
{% for addon in day.getAddons() %}
{% set style = addon.type ?? style %}
{% set statusTitle = (statusTitle ?? '') ~ (addon.title|trans) %}
{% if addon.visibleDuration > 0 %}
{% set statusTitle = statusTitle ~ ' (' ~ addon.visibleDuration|duration(decimal) ~ ')' %}
{% endif %}
{% if not loop.last %}
{% set statusTitle = statusTitle ~ ', ' %}
{% endif %}
{% endfor %}
{% endif %}
<td class="text-end contractDay text-nowrap{% if style is not null %} bg-{{ style }}{% endif %}"{% if statusTitle is not null %} data-toggle="tooltip" data-placement="top" title="{{ statusTitle }}"{% endif %}>
{% if (day.workingTime.expectedTime != 0 or day.workingTime.actualTime != 0 or day.hasAddons()) and (now > day.day or day.workingTime.actualTime > 0) %}
{% if style is not null and statusTitle is not null %}
<i class="{{ style|icon }} fa-xs"></i>
{% endif %}
{% if day.workingTime.expectedTime == 0 and day.workingTime.actualTime == 0 %}
--:--
{% else %}
{{ work_times_result(day.workingTime.expectedTime, day.workingTime.actualTime, decimal) }}
{% endif %}
{{ work_times_result(day.workingTime.expectedTime, day.workingTime.actualTime, decimal) }}
{% endif %}
</td>
{% set dayCount = dayCount + 1 %}

View File

@@ -162,4 +162,72 @@
{% endblock %}
{% endembed %}
{% set opcache_warning = not opcache['enabled'] %}
{% embed '@theme/embeds/collapsible.html.twig' with {open: opcache_warning, boxtype: (opcache_warning ? 'danger' : 'success')} %}
{% block title %}OPCache{% endblock %}
{% block body_class %}p-0{% endblock %}
{% block body %}
{% import "macros/widgets.html.twig" as widgets %}
{% if opcache_warning %}
{{ widgets.alert('danger', 'Could not detect an active OPCache. This will significantly impact the performance of Kimai.') }}
{% endif %}
{% if opcache['status'] is iterable %}
<table class="table table-hover">
<tr>
<th class="text-nowrap w-min">Opcache Enabled</th>
<td class="text-break">{{ widgets.label_boolean(opcache['enabled']) }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Opcache Full</th>
<td class="text-break">{{ widgets.label_boolean(opcache['status']['cache_full']) }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Memory Used</th>
<td class="text-break">{{ (opcache['status']['memory_usage']['used_memory'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
<tr>
<th class="text-nowrap w-min">Memory Free</th>
<td class="text-break">{{ (opcache['status']['memory_usage']['free_memory'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
<tr>
<th class="text-nowrap w-min">Interned-Strings Used</th>
<td class="text-break">{{ (opcache['status']['interned_strings_usage']['used_memory'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
<tr>
<th class="text-nowrap w-min">Interned-Strings Free</th>
<td class="text-break">{{ (opcache['status']['interned_strings_usage']['free_memory'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
<tr>
<th class="text-nowrap w-min">Cached Scripts</th>
<td class="text-break">{{ opcache['status']['opcache_statistics']['num_cached_scripts'] }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Cached Keys</th>
<td class="text-break">{{ opcache['status']['opcache_statistics']['num_cached_keys'] }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Max Keys</th>
<td class="text-break">{{ opcache['status']['opcache_statistics']['max_cached_keys'] }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Hit Rate</th>
<td class="text-break">{{ opcache['status']['opcache_statistics']['opcache_hit_rate']|number_format(2) }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Jit enabled</th>
<td class="text-break">{{ widgets.label_boolean(opcache['status']['jit']['enabled']) }}</td>
</tr>
<tr>
<th class="text-nowrap w-min">Buffer Size</th>
<td class="text-break">{{ (opcache['status']['jit']['buffer_size'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
<tr>
<th class="text-nowrap w-min">Buffer Free</th>
<td class="text-break">{{ (opcache['status']['jit']['buffer_free'] / 1024 / 1024)|number_format(2) }} MB</td>
</tr>
</table>
{% endif %}
{% endblock %}
{% endembed %}
{% endblock %}

View File

@@ -124,17 +124,13 @@
<div class="btn-group me-auto" id="export-buttons" role="group">
{% set allowCreate = is_granted('create_export_template') %}
{% for type, group in buttons %}
{% set btnTitle = ('button.' ~ type)|trans %}
{% if btnTitle == ('button.' ~ type) %}
{% set btnTitle = type|trans %}
{% if type == 'html' %}
{% set type = 'print' %}
{% endif %}
{% set btnTitle = type|trans %}
{% if group|length == 1 %}
{% for id, cfg in group %}
{% set title = cfg.title %}
{% set btnTitle2 = ('button.' ~ title)|trans %}
{% if btnTitle2 != ('button.' ~ title) %}
{% set btnTitle = btnTitle2 %}
{% endif %}
<button type="button" id="export-{{ id }}-button" class="btn btn-primary startExportBtn" data-type="{{ id }}">
{{ btnTitle }}
</button>
@@ -146,13 +142,9 @@
</button>
<div class="dropdown-menu">
{% for id, cfg in group %}
{% set title = cfg.title %}
{% set btnTitle = id|trans({}, 'export') %}
{% if btnTitle == id %}
{% set btnTitle = title|trans %}
{% endif %}
{% if btnTitle == id %}
{% set btnTitle = id|split('.')|first|replace({'-': ' ', '_': ' '})|split(' ')|map(t => t|capitalize)|join(' ') %}
{% set btnTitle = (cfg.title)|trans %}
{% if loop.first %}
{% set btnTitle = 'default'|trans %}
{% endif %}
<a href="#" class="dropdown-item startExportBtn" data-type="{{ id }}">
{{ btnTitle }}

View File

@@ -6,7 +6,7 @@
{% set showCustomerSummary = false %}
{% set decimal = true %}
{% set showDateTimeShort = true %}
{% block title %}{{ 'timesheet.pdf.twig'|trans({}, 'export') }}{% endblock %}
{% block title %}{{ 'timesheet'|trans }}{% endblock %}
{% block description %}
{% if entry.description is not empty %}
{{ entry.description|desc2html }}