0
0
Fork 0
mirror of https://github.com/kevinpapst/kimai2.git synced 2025-03-17 06:22:38 +00:00

Release 2.0.21 ()

* increase padding in wizard
* fix theme chooser in wizard
* improve dynamic export columns in PDFs
* added label for total column
* bump theme bundle
* improve avatar list spacing
* be more flexible parsing times - fixes 
This commit is contained in:
Kevin Papst 2023-05-17 15:02:10 +02:00 committed by GitHub
parent 29624354a2
commit 9bd5965ecd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 148 additions and 113 deletions

View file

@ -147,18 +147,49 @@ export default class KimaiTimesheetForm extends KimaiFormPlugin {
return null;
}
const date = this.getDateUtils().fromFormat(
this._beginDate.value + ' ' + this._beginTime.value,
this._beginDate.dataset['format'] + ' ' + this._beginTime.dataset['format'],
);
let date = this._parseBegin(this._beginTime.dataset['format']);
if (date.invalid) {
return null;
date = this._parseBegin(this._fixTimeFormat(this._beginTime.dataset['format']));
if (date.invalid) {
return null;
}
}
return date;
}
_parseBegin(timeFormat)
{
return this.getDateUtils().fromFormat(
this._beginDate.value + ' ' + this._beginTime.value,
this._beginDate.dataset['format'] + ' ' + timeFormat,
);
}
_parseEnd(endDate, timeFormat)
{
let date = this.getDateUtils().fromFormat(
endDate.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + timeFormat,
);
if (date.invalid) {
date = this.getDateUtils().fromFormat(
endDate.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._fixTimeFormat(timeFormat),
);
}
return date;
}
_fixTimeFormat(format)
{
return format.replace('HH', 'H').replace('hh', 'h');
}
/**
* @returns {DateTime|null}
* @private
@ -169,17 +200,11 @@ export default class KimaiTimesheetForm extends KimaiFormPlugin {
return null;
}
let date = this.getDateUtils().fromFormat(
DateTime.now().toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._endTime.dataset['format'],
);
let date = this._parseEnd(DateTime.now(), this._endTime.dataset['format']);
const begin = this._getBegin();
if (begin !== null) {
date = this.getDateUtils().fromFormat(
begin.toFormat('yyyy-LL-dd') + ' ' + this._endTime.value,
'yyyy-LL-dd ' + this._endTime.dataset['format'],
);
date = this._parseEnd(begin, this._endTime.dataset['format']);
if (date < begin) {
date = date.plus({days: 1});

View file

@ -42,5 +42,5 @@ table.dataTable.table > tbody > tr > td {
/* decreases the margin between avatars, see https://github.com/tabler/tabler/issues/1567 */
.avatar-list-stacked .avatar {
margin-right: calc(var(--tblr-avatar-size)*-.1)!important;
margin-right: calc(var(--tblr-avatar-size)*-.2)!important;
}

View file

@ -34,7 +34,7 @@
"friendsofsymfony/rest-bundle": "^3.0",
"gedmo/doctrine-extensions": "^3.6",
"jms/serializer-bundle": "^5.0",
"kevinpapst/tabler-bundle": "^0.17",
"kevinpapst/tabler-bundle": "^0.18",
"league/csv": "^9.4",
"mpdf/mpdf": "^8.0",
"nelmio/api-doc-bundle": "^4.0",

14
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "63b69c5c8020a78b308210425547d46c",
"content-hash": "aedc077bff6e5890b17415527e991e17",
"packages": [
{
"name": "bacon/bacon-qr-code",
@ -2416,16 +2416,16 @@
},
{
"name": "kevinpapst/tabler-bundle",
"version": "0.17",
"version": "0.18",
"source": {
"type": "git",
"url": "https://github.com/kevinpapst/TablerBundle.git",
"reference": "0061d82a28059cf876cf819f1780607aac131d32"
"reference": "f438b55cd393331385700a30515d3966747ecd7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/0061d82a28059cf876cf819f1780607aac131d32",
"reference": "0061d82a28059cf876cf819f1780607aac131d32",
"url": "https://api.github.com/repos/kevinpapst/TablerBundle/zipball/f438b55cd393331385700a30515d3966747ecd7a",
"reference": "f438b55cd393331385700a30515d3966747ecd7a",
"shasum": ""
},
"require": {
@ -2474,7 +2474,7 @@
"description": "Admin/Backend theme bundle for Symfony based on Tabler.io",
"support": {
"issues": "https://github.com/kevinpapst/TablerBundle/issues",
"source": "https://github.com/kevinpapst/TablerBundle/tree/0.17"
"source": "https://github.com/kevinpapst/TablerBundle/tree/0.18"
},
"funding": [
{
@ -2486,7 +2486,7 @@
"type": "github"
}
],
"time": "2023-05-15T18:25:59+00:00"
"time": "2023-05-16T16:30:10+00:00"
},
{
"name": "laminas/laminas-escaper",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -3,10 +3,10 @@
"app": {
"js": [
"/build/runtime.f0079159.js",
"/build/app.45d541e0.js"
"/build/app.70a820f6.js"
],
"css": [
"/build/app.66162a27.css"
"/build/app.f43008a1.css"
]
},
"export-pdf": {
@ -63,8 +63,8 @@
},
"integrity": {
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
"/build/app.45d541e0.js": "sha384-KhCwP7jLZJ8+g02Lr+oITVZ8woE+EU01t/VQNuDyHmpVPCVggaaoI9EU9lJeB62l",
"/build/app.66162a27.css": "sha384-TeR8dC4yDJMVshAZ+sa3WotB4RqTHOiTtHROHg7jXEE29WCabeBlXB6MKiPdnsu3",
"/build/app.70a820f6.js": "sha384-WKz8wOwY8EYT1ncPkMRnEE3q5LnP76keOZxTD410dXpsowUktUg+vWUqDhVXwLat",
"/build/app.f43008a1.css": "sha384-pZxN+QyK3/ggIPic7tC9sHJImYoGGtVX2CRA2JqH/BK5RYd2UGOsAhb5VXzjLX0l",
"/build/export-pdf.d367a32e.js": "sha384-Z5baqnzjI636nYFs4g63ViIKBZKRW4Jhv/7PQmTEQlqhfA7eK0vUMUtiyy0R5A9u",
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
"/build/invoice.2604495e.js": "sha384-D6JvhGSqlx7z72b/qD3nF3QDXPy+XsCSRGtWfs1icjDKOcd2UzuXwuSa/E1Fg2TJ",

View file

@ -1,6 +1,6 @@
{
"build/app.css": "/build/app.66162a27.css",
"build/app.js": "/build/app.45d541e0.js",
"build/app.css": "/build/app.f43008a1.css",
"build/app.js": "/build/app.70a820f6.js",
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
"build/export-pdf.js": "/build/export-pdf.d367a32e.js",
"build/invoice.css": "/build/invoice.5bea118e.css",

View file

@ -17,11 +17,11 @@ class Constants
/**
* The current release version
*/
public const VERSION = '2.0.20';
public const VERSION = '2.0.21';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 20020;
public const VERSION_ID = 20021;
/**
* The software name
*/

View file

@ -80,7 +80,7 @@
</tbody>
<tfoot>
<tr class="summary">
<td></td>
<td>{{ 'sum.total'|trans }}</td>
<td class="text-end total">
{{ work_times_result(summaries.expectedTime, summaries.actualTime, decimal) }}
</td>

View file

@ -6,6 +6,7 @@
{% set showCustomerSummary = showCustomerSummary ?? true %}
{% set showTotalSummary = showTotalSummary ?? true %}
{% set showDateTimeShort = showDateTimeShort ?? false %}
{% set showSummaryHourlyRate = showSummaryHourlyRate ?? false %}
{% set now = create_date('now', app.user) %}
{% set decimal = decimal ?? false %}
{# this is only triggered, if a user exports from his personal timesheet screen #}
@ -14,8 +15,26 @@
{# if exporting via the admin screen, users without view_rate_own_timesheet might still see their own rates #}
{% set showRateColumn = is_granted('view_rate_own_timesheet') %}
{% endif %}
{% set summaryColumns = ['customer', 'project'] %}
{% if showTimeBudget %}
{% set summaryColumns = summaryColumns|merge(['timeBudget']) %}
{% endif %}
{% if showRateBudget %}
{% set summaryColumns = summaryColumns|merge(['budget']) %}
{% endif %}
{% if showSummaryHourlyRate %}
{% set summaryColumns = summaryColumns|merge(['hourlyRate']) %}
{% endif %}
{% set summaryColumns = summaryColumns|merge(['duration']) %}
{% if showRateColumn %}
{% if showInternalRate %}
{% set summaryColumns = summaryColumns|merge(['internalRate']) %}
{% endif %}
{% set summaryColumns = summaryColumns|merge(['rate']) %}
{% endif %}
<html{% if app.request is defined and app.request is not null %} lang="{{ app.request.locale }}"{% endif %}>
<head>
<title>{% block document_title %}{{ 'export'|trans }}{% endblock %}</title>
{% block styles %}
<style>
{{ encore_entry_css_source('export-pdf')|raw }}
@ -64,21 +83,15 @@ mpdf-->
<table class="items">
<thead>
<tr>
<th>{{ 'customer'|trans }}</th>
<th>{{ 'project'|trans }}</th>
{% if showTimeBudget %}
<th class="center">{{ 'timeBudget'|trans }}</th>
{% endif %}
{% if showRateBudget %}
<th class="center">{{ 'budget'|trans }}</th>
{% endif %}
<th class="center">{{ 'duration'|trans }}</th>
{% if showRateColumn %}
{% if showInternalRate %}
<th class="center">{{ 'internalRate'|trans }}</th>
{% for summaryColumn in summaryColumns %}
{% if summaryColumn == 'customer' %}
<th>{{ 'customer'|trans }}</th>
{% elseif summaryColumn == 'project' %}
<th>{{ 'project'|trans }}</th>
{% else %}
<th class="center">{{ summaryColumn|trans }}</th>
{% endif %}
<th class="center">{{ 'rate'|trans }}</th>
{% endif %}
{% endfor %}
</tr>
</thead>
<tbody>
@ -106,21 +119,17 @@ mpdf-->
{% endif %}
{% if customer is not same as(summary.customer) %}
<tr class="summary">
<td colspan="2">
</td>
{% if showTimeBudget %}
<td></td>
{% endif %}
{% if showRateBudget %}
<td></td>
{% endif %}
<td class="totals duration">{{ customerDuration|duration(decimal) }}</td>
{% if showRateColumn %}
{% if showInternalRate %}
{% for summaryColumn in summaryColumns %}
{% if summaryColumn == 'duration' %}
<td class="totals duration">{{ customerDuration|duration(decimal) }}</td>
{% elseif summaryColumn == 'internalRate' %}
<td class="totals cost">{{ customerInternalRate|money(customerCurrency) }}</td>
{% elseif summaryColumn == 'rate' %}
<td class="totals cost">{{ customerRate|money(customerCurrency) }}</td>
{% else %}
<td></td>
{% endif %}
<td class="totals cost">{{ customerRate|money(customerCurrency) }}</td>
{% endif %}
{% endfor %}
</tr>
{% set customerCurrency = summary.currency %}
{% set customer = summary.customer %}
@ -130,29 +139,34 @@ mpdf-->
{% set customerCount = 0 %}
{% endif %}
<tr class="{{ cycle(['odd', 'even'], customerCount) }}">
<td>{{ summary.customer }}</td>
<td>{{ summary.project }}</td>
{% if showTimeBudget %}
<td class="center">
{% if budgets[id] is defined and budgets[id].time_left > 0 %}
{{ budgets[id].time_left|duration(decimal) }}
{% endif %}
</td>
{% endif %}
{% if showRateBudget %}
<td class="center">
{% if budgets[id] is defined and budgets[id].money_left > 0 %}
{{ budgets[id].money_left|money(summary.currency) }}
{% endif %}
</td>
{% endif %}
<td class="duration">{{ summary.duration|duration(decimal) }}</td>
{% if showRateColumn %}
{% if showInternalRate %}
{% for summaryColumn in summaryColumns %}
{% if summaryColumn == 'customer' %}
<td>{{ summary.customer }}</td>
{% elseif summaryColumn == 'project' %}
<td>{{ summary.project }}</td>
{% elseif summaryColumn == 'timeBudget' %}
<td class="center">
{% if budgets[id] is defined and budgets[id].time_left > 0 %}
{{ budgets[id].time_left|duration(decimal) }}
{% endif %}
</td>
{% elseif summaryColumn == 'budget' %}
<td class="center">
{% if budgets[id] is defined and budgets[id].money_left > 0 %}
{{ budgets[id].money_left|money(summary.currency) }}
{% endif %}
</td>
{% elseif summaryColumn == 'hourlyRate' %}
{% set summaryHourlyRate = summary.duration/3600 %}
<td class="cost">{{ summaryHourlyRate > 0 ? (summary.rate/summaryHourlyRate)|money(summary.currency) : '' }}</td>
{% elseif summaryColumn == 'duration' %}
<td class="duration">{{ summary.duration|duration(decimal) }}</td>
{% elseif summaryColumn == 'internalRate' %}
<td class="cost">{{ summary.rate_internal|money(summary.currency) }}</td>
{% elseif summaryColumn == 'rate' %}
<td class="cost">{{ summary.rate|money(summary.currency) }}</td>
{% endif %}
<td class="cost">{{ summary.rate|money(summary.currency) }}</td>
{% endif %}
{% endfor %}
</tr>
{% set customerDuration = customerDuration + summary.duration %}
{% set customerRate = customerRate + summary.rate %}
@ -161,20 +175,17 @@ mpdf-->
{% endfor %}
{% if showCustomerSummary and customer is not same as(null) %}
<tr class="summary">
<td colspan="2"></td>
{% if showTimeBudget %}
<td></td>
{% endif %}
{% if showRateBudget %}
<td></td>
{% endif %}
<td class="totals duration">{{ customerDuration|duration(decimal) }}</td>
{% if showRateColumn %}
{% if showInternalRate %}
{% for summaryColumn in summaryColumns %}
{% if summaryColumn == 'duration' %}
<td class="totals duration">{{ customerDuration|duration(decimal) }}</td>
{% elseif summaryColumn == 'internalRate' %}
<td class="totals cost">{{ customerInternalRate|money(customerCurrency) }}</td>
{% elseif summaryColumn == 'rate' %}
<td class="totals cost">{{ customerRate|money(customerCurrency) }}</td>
{% else %}
<td></td>
{% endif %}
<td class="totals cost">{{ customerRate|money(customerCurrency) }}</td>
{% endif %}
{% endfor %}
</tr>
{% endif %}
{% if showTotalSummary and not multiCurrency %}
@ -182,19 +193,17 @@ mpdf-->
<td class="totals" colspan="2">
{{ 'sum.total'|trans }}
</td>
{% if showTimeBudget %}
<td></td>
{% endif %}
{% if showRateBudget %}
<td></td>
{% endif %}
<td class="totals duration">{{ totalDuration|duration(decimal) }}</td>
{% if showRateColumn %}
{% if showInternalRate %}
<td class="totals cost">{{ totalInternalRate|money(customerCurrency) }}</td>
{% for summaryColumn in summaryColumns %}
{% if summaryColumn == 'duration' %}
<td class="totals duration">{{ totalDuration|duration(decimal) }}</td>
{% elseif summaryColumn == 'internalRate' %}
<td class="totals cost">{{ totalInternalRate|money(customerCurrency) }}</td>
{% elseif summaryColumn == 'rate' %}
<td class="totals cost">{{ totalRate|money(customerCurrency) }}</td>
{% elseif summaryColumn not in ['customer', 'project'] %}
<td></td>
{% endif %}
<td class="totals cost">{{ totalRate|money(customerCurrency) }}</td>
{% endif %}
{% endfor %}
</tr>
{% endif %}
</tbody>

View file

@ -2,7 +2,7 @@
{% from '@Tabler/components/button.html.twig' import button %}
{% block wizard_content %}
<div class="card-body text-center py-4 p-sm-5">
<div class="card-body text-center py-4 p-sm-7">
<img src="{{ asset('wizard/done.png') }}" height="120" class="mb-n2" alt="Illustration by Katerina Limpitsouni from https://undraw.co/">
<h1 class="mt-5">{{ 'wizard.done.title'|trans({}, 'wizard') }}</h1>
<p class="text-body-secondary">{{ 'wizard.done.description'|trans({}, 'wizard') }}</p>

View file

@ -1,7 +1,7 @@
{% extends 'wizard/layout.html.twig' %}
{% block wizard_content %}
<div class="card-body text-center py-4 p-sm-5">
<div class="card-body text-center py-4 p-sm-7">
<img src="{{ asset('wizard/time-management.png') }}" height="120" class="mb-n2" alt="Illustration by Katerina Limpitsouni from https://undraw.co/">
<h1 class="mt-5">{{ 'wizard.intro.title'|trans({}, 'wizard') }}</h1>
<p class="text-body-secondary">{{ 'wizard.intro.description'|trans({}, 'wizard') }}</p>

View file

@ -1,7 +1,7 @@
{% extends 'wizard/layout.html.twig' %}
{% block wizard_content %}
<div class="card-body text-center py-4 p-sm-5">
<div class="card-body text-center py-4 p-sm-6">
<h1 class="mt-2">{{ 'wizard.profile.title'|trans({}, 'wizard') }}</h1>
<p class="text-body-secondary">{{ 'wizard.profile.description'|trans({}, 'wizard') }}</p>
</div>
@ -19,10 +19,11 @@
const skinChooser = document.getElementById('form_skin');
if (skinChooser !== null) {
skinChooser.addEventListener('change', () => {
document.body.classList.remove('theme-light');
document.body.classList.remove('theme-default');
document.body.classList.remove('theme-dark');
document.body.classList.add('theme-' + skinChooser.value);
document.querySelectorAll('[data-bs-theme]').forEach(
element => {
element.dataset['bsTheme'] = (skinChooser.value === 'default' ? 'light' : 'dark');
}
);
});
}