Release 2.39 (#5604)

* prepare audit via annotation
* default calendar slot label distance of 1h
+ replace freestyle config with dropdown
* added missing return definition in callbacks
* refactor view name handling
* dispatch calendar view changes and push them into the URL to be able to reload the poage
* bump packages
* fix timezone issue in calendar sum calculation
* fixes #5618 resetRates()
* show expected daily hours in working-contract screen
This commit is contained in:
Kevin Papst
2025-08-30 11:41:17 +02:00
committed by GitHub
parent 4920ea5075
commit a4d658b821
85 changed files with 987 additions and 516 deletions

View File

@@ -9,9 +9,19 @@
{% if form is not null %}
{% embed '@theme/embeds/card.html.twig' %}
{% block box_body %}
{{ form_start(form) }}
{{ form_start(form, {attr: {id: 'calendar-form'}}) }}
{% if form.user is defined %}
{{ form_row(form.user) }}
{% set user_class = '' %}
{% if form.user.vars.choices|length < 2 %}
{% set user_class = 'd-none' %}
{% endif %}
{{ form_row(form.user, {row_attr: {class: user_class}}) }}
{% endif %}
{% if form.date is defined %}
{{ form_row(form.date, {row_attr: {class: 'd-none'}}) }}
{% endif %}
{% if form.view is defined %}
{{ form_row(form.view, {row_attr: {class: 'd-none'}}) }}
{% endif %}
{{ form_rest(form) }}
{{ form_end(form) }}
@@ -92,15 +102,33 @@
document.addEventListener('kimai.timesheetUpdate', reloader);
document.addEventListener('kimai.timesheetDelete', reloader);
document.addEventListener('kimai.calendar.changeDate', function(event) {
var queryParams = new URLSearchParams(window.location.search);
const dateSelect = document.getElementById('date');
if (dateSelect !== null) {
dateSelect.value = event.detail.date;
queryParams.set('date', event.detail.date);
}
const viewSelect = document.getElementById('view');
if (viewSelect !== null) {
viewSelect.value = event.detail.view;
queryParams.set('view', event.detail.view);
}
history.replaceState(null, null, "?" + queryParams.toString());
});
document.addEventListener('kimai.initialized', function(event) {
const kimai = event.detail.kimai;
let calendarOptions = {
initialDate: '{{ initial_date|report_date }}',
dragdrop: {
container: '.external-events',
items: '.external-event',
},
initialView: '{{ app.user.getPreferenceValue('calendar_initial_view') }}',
initialView: '{{ initial_view }}',
translations: {
customer: '{{ 'customer'|trans }}',
project: '{{ 'project'|trans }}',

View File

@@ -222,6 +222,38 @@
{% endembed %}
{% endif %}
{% if withWorkHourConfiguration %}
{% set expectedWeekTimes = 0 %}
{% for day in days %}
{% set expectedWeekTimes = expectedWeekTimes + day.duration %}
{% endfor %}
{% embed '@theme/embeds/collapsible.html.twig' with {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 }}
&nbsp;
{{ status_duration(expectedWeekTimes|duration) }}
{% endblock %}
{% block body %}
<div class="datagrid">
{% for day in days %}
<div class="datagrid-item">
<div class="datagrid-title">{{ day.date|day_name }}</div>
<div class="datagrid-content">
{% if day.duration is not null %}
{{ day.duration|duration }}
{% else %}
&ndash;
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% endblock %}
{% endembed %}
{% endif %}
{% for controller in boxes %}
{{ render(controller(controller, {'year': year, 'boxConfiguration': box_configuration})) }}
{% endfor %}

View File

@@ -150,6 +150,25 @@
</div>
{%- endblock date_widget %}
{% block day_widget -%}
{% set format = 'y-MM-D' %}
{% set jsFormat = format|js_format %}
{% set attr = attr|merge({'pattern': format|pattern, 'autocomplete': 'off', 'data-format': jsFormat}) -%}
<div class="input-group">
<div class="input-group-text">
<a href="#" data-form-widget="date-now" data-format="{{ jsFormat }}" data-target="{{ id }}">{{ icon('calendar') }}</a>
</div>
{{- block('form_widget_simple') -}}
{% if not required %}
<span class="input-group-text">
<a href="javascript: void(0)" class="link-secondary fs-5" onclick="document.getElementById('{{ id }}').value = ''">
{{ icon('cancel') }}
</a>
</span>
{% endif %}
</div>
{%- endblock day_widget %}
{% block time_widget -%}
{%- set attr = attr|merge({'pattern': time_format|pattern, 'autocomplete': 'off', 'data-timepicker': 'on', 'data-format': js_format, 'placeholder': time_format}) -%}
<div class="input-group">