* bump version
* fix translation ids
* added css classes to modify form with custom css
* improve export pdf file names
* respect financial year in new report
* added new InvoiceCalculator: price
* upgrade packages and node-sass to v7
* title pattern for customer, project and activity via API
* support negative money without currency
* fix sub-locale in print export template
* fix overbooking validation for monthly budget
* fix copying entities with different set of custom-fields compared to the current configuration
This commit is contained in:
Kevin Papst
2022-02-25 20:41:56 +01:00
committed by GitHub
parent 34649d809e
commit c0168ecc5b
53 changed files with 1222 additions and 611 deletions

View File

@@ -288,28 +288,8 @@
{% block javascripts %}
{# no call to parent(), as we use a custom built for the frontend assets and don't want the default <script> #}
<script type="text/javascript">
window.addEventListener('load', function() {
var loader = new KimaiWebLoader(
{
formatDuration: '{{ get_format_duration() }}',
login: '{{ path('fos_user_security_login') }}',
locale: '{{ app.request.locale }}',
first_dow_iso: {{ iso_day_by_name(app.user.firstDayOfWeek) }},
twentyFourHours: {{ app.user.is24Hour() ? 'true' : 'false' }},
autoComplete: {{ kimai_config.themeAutocompleteCharacters }},
defaultColor: '{{ constant('App\\Constants::DEFAULT_COLOR') }}',
updateBrowserTitle: {% if app.user.preferenceValue('theme.update_browser_title') %}true{% else %}false{% endif %}
},
{
{% for key, translation in javascript_translations() -%}
'{{ key }}': '{{ translation.0|trans({}, translation.1)|escape('js') }}',
{%- endfor %}
}
);
window.kimai = loader.getKimai();
});
</script>
{% import "macros/webloader.html.twig" as webloader %}
{{ webloader.init_frontend_loader() }}
{% set event = trigger(constant('App\\Event\\ThemeEvent::JAVASCRIPT')) %}
{{ event.content|raw }}
{% endblock %}

View File

@@ -95,7 +95,11 @@
</button>
<ul class="dropdown-menu">
{% for button in group %}
<li><a href="#" class="startExportBtn" data-type="{{ button.id }}">{{ (button.id)|trans({}, 'export') }}</a></li>
{% set btnTitle = (button.id)|trans({}, 'export') %}
{% if btnTitle == button.id %}
{% set btnTitle = button.id|split('.')|first|replace({'-': ' ', '_': ' '})|split(' ')|map(t => t|capitalize)|join(' ') %}
{% endif %}
<li><a href="#" class="startExportBtn" data-type="{{ button.id }}">{{ btnTitle }}</a></li>
{% endfor %}
</ul>
</div>

View File

@@ -1,6 +1,7 @@
{% extends 'export/layout.html.twig' %}
{% import "macros/widgets.html.twig" as widgets %}
{% import "macros/datatables.html.twig" as tables %}
{% extends 'export/layout.html.twig' %}
{% import "macros/webloader.html.twig" as webloader %}
{% block document_title %}{{ 'export.title'|trans }}{% endblock %}
@@ -51,27 +52,25 @@
}) %}
{% block javascripts %}
{{ webloader.init_frontend_loader() }}
<script type="text/javascript">
let initialized = false;
window.addEventListener('load', function() {
var loader = new KimaiWebLoader({
formatDuration: '{{ get_format_duration() }}',
locale: '{{ app.request.locale }}',
}, {});
var DATES = loader.getKimai().getPlugin('date');
document.addEventListener('kimai.initialized', function(event) {
const KIMAI = event.detail.kimai;
const DATES = KIMAI.getPlugin('date');
document.getElementById('duration-decimal').addEventListener('click', function(event) {
var spans = document.getElementsByClassName('duration-format');
for (var span of spans) {
var duration = span.dataset['duration'];
let spans = document.getElementsByClassName('duration-format');
for (let span of spans) {
let duration = span.dataset['duration'];
if (duration === undefined) {
continue;
}
if (!event.target.checked) {
span.innerHTML = DATES.formatSeconds(duration);
} else {
span.innerHTML = (new Intl.NumberFormat('{{ app.request.locale }}', {maximumFractionDigits: 2}).format(duration / 3600));
span.innerHTML = (new Intl.NumberFormat('{{ app.request.locale|replace({'_': '-'}) }}', {maximumFractionDigits: 2}).format(duration / 3600));
}
}
saveVisibility();
@@ -96,36 +95,36 @@
saveVisibility();
});
document.getElementById('summary-timeBudget').addEventListener('click', function(event) {
var cells = document.getElementsByClassName('export-timeBudget');
for (var columnCell of cells) {
let cells = document.getElementsByClassName('export-timeBudget');
for (let columnCell of cells) {
columnCell.style.display = event.target.checked ? 'table-cell' : 'none';
}
saveVisibility();
});
document.getElementById('summary-budget').addEventListener('click', function(event) {
var cells = document.getElementsByClassName('export-budget');
for (var columnCell of cells) {
let cells = document.getElementsByClassName('export-budget');
for (let columnCell of cells) {
columnCell.style.display = event.target.checked ? 'table-cell' : 'none';
}
saveVisibility();
});
document.getElementById('summary-duration').addEventListener('click', function(event) {
var cells = document.getElementsByClassName('summary-duration');
for (var columnCell of cells) {
let cells = document.getElementsByClassName('summary-duration');
for (let columnCell of cells) {
columnCell.style.display = event.target.checked ? 'table-cell' : 'none';
}
saveVisibility();
});
document.getElementById('summary-rate').addEventListener('click', function(event) {
var cells = document.getElementsByClassName('summary-rate');
for (var columnCell of cells) {
let cells = document.getElementsByClassName('summary-rate');
for (let columnCell of cells) {
columnCell.style.display = event.target.checked ? 'table-cell' : 'none';
}
saveVisibility();
});
document.getElementById('summary-rate-internal').addEventListener('click', function(event) {
var cells = document.getElementsByClassName('summary-rate-internal');
for (var columnCell of cells) {
let cells = document.getElementsByClassName('summary-rate-internal');
for (let columnCell of cells) {
columnCell.style.display = event.target.checked ? 'table-cell' : 'none';
}
saveVisibility();
@@ -139,17 +138,17 @@
saveVisibility();
});
var columnCheckboxes = document.getElementsByClassName('column-visibility-changer');
let columnCheckboxes = document.getElementsByClassName('column-visibility-changer');
for (var checkbox of columnCheckboxes) {
for (let checkbox of columnCheckboxes) {
checkbox.addEventListener('click', function(event) {
changeVisibility(event.target.name, event.target.checked);
});
}
var editableTitles = document.querySelectorAll('[contenteditable=true]');
let editableTitles = document.querySelectorAll('[contenteditable=true]');
for (var editable of editableTitles) {
for (let editable of editableTitles) {
editable.addEventListener('input', function(event) {
if (event.target.innerText === '') {
return;
@@ -200,8 +199,8 @@
function changeVisibility(column, visible)
{
var cells = document.getElementsByClassName('column-' + column);
for (var columnCell of cells) {
let cells = document.getElementsByClassName('column-' + column);
for (let columnCell of cells) {
columnCell.style.display = visible ? 'table-cell' : 'none';
}
saveVisibility();
@@ -209,9 +208,9 @@
function changedDateFormat(formatType, className)
{
var elements = document.getElementsByClassName(className);
for (var elem of elements) {
var formattedDate = elem.dataset[formatType];
let elements = document.getElementsByClassName(className);
for (let elem of elements) {
let formattedDate = elem.dataset[formatType];
if (formattedDate === undefined) {
continue;
}
@@ -242,9 +241,9 @@
function resetExport()
{
var editableTitles = document.querySelectorAll('[contenteditable=true]');
let editableTitles = document.querySelectorAll('[contenteditable=true]');
for (var editable of editableTitles) {
for (let editable of editableTitles) {
editable.innerText = editable.dataset['original'];
}
@@ -252,7 +251,6 @@
const form = document.getElementsByTagName('form')[0];
form.reset();
}
</script>
{% endblock %}

View File

@@ -0,0 +1,31 @@
{% macro init_frontend_loader() %}
{% set configurations = javascript_configurations(app.user)|merge({
login: path('fos_user_security_login'),
locale: app.request.locale,
first_dow_iso: iso_day_by_name(app.user.firstDayOfWeek),
autoComplete: kimai_config.themeAutocompleteCharacters,
}) %}
<script type="text/javascript">
window.addEventListener('load', function() {
const loader = new KimaiWebLoader({
{%- for name, value in configurations -%}
{%- if value is same as (true) -%}
{{ name }}:true
{%- elseif value is same as (false) -%}
{{ name }}:false
{%- elseif value is number -%}
{{ name }}:{{ value }}
{%- else -%}
{{ name }}:'{{ value }}'
{%- endif -%}
{%- if not loop.last %},{% endif -%}
{%- endfor -%}
},{
{%- for key, translation in javascript_translations() -%}
'{{ key }}': '{{ translation.0|trans({}, translation.1)|escape('js') }}'{% if not loop.last %},{% endif %}
{%- endfor -%}
});
window.kimai = loader.getKimai();
});
</script>
{% endmacro %}

View File

@@ -7,7 +7,7 @@
{% embed '@AdminLTE/Widgets/box-widget.html.twig' %}
{% from "macros/widgets.html.twig" import nothing_found %}
{% block box_before %}
{{ form_start(form, {'attr': {'class': 'form-inline kimai-1.17', 'id': 'user-list-filter-form'}}) }}
{{ form_start(form, {'attr': {'class': 'form-inline', 'id': 'user-list-filter-form'}}) }}
{% endblock %}
{% block box_after %}
{{ form_end(form) }}

View File

@@ -43,22 +43,22 @@
</div>
{% endif %}
{% if form.customer is defined %}
{{ form_row(form.customer) }}
{{ form_row(form.customer, {'row_attr': {'class': 'timesheet_edit_form_row_customer'}}) }}
{% endif %}
{% if form.project is defined %}
{{ form_row(form.project) }}
{{ form_row(form.project, {'row_attr': {'class': 'timesheet_edit_form_row_project'}}) }}
{% endif %}
{% if form.activity is defined %}
{{ form_row(form.activity) }}
{{ form_row(form.activity, {'row_attr': {'class': 'timesheet_edit_form_row_activity'}}) }}
{% endif %}
{% if form.description is defined %}
{{ form_row(form.description) }}
{{ form_row(form.description, {'row_attr': {'class': 'timesheet_edit_form_row_description'}}) }}
{% endif %}
{% if form.tags is defined %}
{{ form_row(form.tags) }}
{{ form_row(form.tags, {'row_attr': {'class': 'timesheet_edit_form_row_tags'}}) }}
{% endif %}
{% if form.user is defined %}
{{ form_row(form.user) }}
{{ form_row(form.user, {'row_attr': {'class': 'timesheet_edit_form_row_user'}}) }}
{% endif %}
{% if form.users is defined or form.teams is defined %}
{% set uLength = 12 %}
@@ -81,10 +81,10 @@
{% if form.fixedRate is defined and form.hourlyRate is defined %}
<div class="row">
<div class="col-md-6">
{{ form_row(form.fixedRate) }}
{{ form_row(form.fixedRate, {'row_attr': {'class': 'timesheet_edit_form_row_fixedRate'}}) }}
</div>
<div class="col-md-6">
{{ form_row(form.hourlyRate) }}
{{ form_row(form.hourlyRate, {'row_attr': {'class': 'timesheet_edit_form_row_hourlyRate'}}) }}
</div>
</div>
{% endif %}
@@ -98,12 +98,12 @@
<div class="row">
{% if form.exported is defined %}
<div class="col-md-{{ ebLength }}">
{{ form_row(form.exported) }}
{{ form_row(form.exported, {'row_attr': {'class': 'timesheet_edit_form_row_exported'}}) }}
</div>
{% endif %}
{% if form.billable is defined %}
<div class="col-md-{{ ebLength }}">
{{ form_row(form.billable) }}
{{ form_row(form.billable, {'row_attr': {'class': 'timesheet_edit_form_row_billable'}}) }}
</div>
{% endif %}
</div>