Release 2.28 (#5253)

* fix year in dashboard
* make batch actions accessible via javascript
* bump packages
* remove BOM from CSV
* rebuild assets
* fix duplicated automated-email warning
This commit is contained in:
Kevin Papst
2025-01-18 01:49:16 +01:00
committed by GitHub
parent 1b3ff212d2
commit f2fb338539
40 changed files with 459 additions and 446 deletions

View File

@@ -21,7 +21,7 @@ version-resolver:
- 'translation'
default: patch
template: |
**Compatible with PHP 8.1 to 8.3**
**Compatible with PHP 8.1 to 8.4**
$CHANGES

View File

@@ -13,6 +13,11 @@ import KimaiPlugin from '../KimaiPlugin';
export default class KimaiMultiUpdateTable extends KimaiPlugin {
getId()
{
return 'datatable-batch-action';
}
init()
{
if (document.getElementsByClassName('multi_update_all').length === 0) {
@@ -24,17 +29,11 @@ export default class KimaiMultiUpdateTable extends KimaiPlugin {
const element = document.querySelector('div.page-body');
element.addEventListener('change', (event) => {
if (event.target.matches('.multi_update_all')) {
// the "check all" checkbox in the upper start corner of the table
const checked = event.target.checked;
const table = event.target.closest('table');
for (const element of table.querySelectorAll('.multi_update_single')) {
element.checked = checked;
}
this._toggleForm(table);
this.toggle(event.target.checked, event.target.closest('table'));
event.stopPropagation();
} else if (event.target.matches('.multi_update_single')) {
// single checkboxes in front of each row
this._toggleForm(event.target.closest('table'));
this._toggleDatatable(event.target.closest('table'));
event.stopPropagation();
}
});
@@ -58,11 +57,54 @@ export default class KimaiMultiUpdateTable extends KimaiPlugin {
});
}
/**
* @param {boolean} checked
* @param {HTMLTableElement} table
*/
toggle(checked, table)
{
for (const element of table.querySelectorAll('.multi_update_single')) {
element.checked = checked;
}
this._toggleDatatable(table);
}
/**
* @param {boolean} checked
*/
toggleAll(checked)
{
for (const element of document.querySelectorAll('.multi_update_all')) {
this._toggleAll(checked, element);
}
}
/**
* @param {boolean} checked
* @param {string} name
*/
toggleByName(checked, name)
{
for (const element of document.querySelectorAll('#multi_update_all_' + name)) {
this._toggleAll(checked, element);
}
}
/**
* @param {boolean} checked
* @param {Element} name
*/
_toggleAll(checked, element)
{
element.checked = checked;
this.toggle(checked, element.closest('table'));
}
/**
* @param {HTMLTableElement} table
* @private
*/
_toggleForm(table)
_toggleDatatable(table)
{
const card = table.closest('div.card.data_table');

View File

@@ -28,7 +28,7 @@
"azuyalabs/yasumi": "^2.6",
"composer/semver": "^3.3",
"doctrine/doctrine-bundle": "^2.7",
"doctrine/doctrine-migrations-bundle": "^3.0",
"doctrine/doctrine-migrations-bundle": "3.3.1",
"doctrine/orm": "^2.8",
"endroid/qr-code": "^4.8",
"erusev/parsedown": "^1.6",

683
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "kimai2",
"name": "kimai",
"homepage": "https://github.com/kimai/kimai",
"license": "MIT",
"license": "AGPL",
"maintainers": [
{
"name": "Kevin Papst",

View File

@@ -452,11 +452,6 @@ parameters:
count: 1
path: src/Command/ResetDevelopmentCommand.php
-
message: "#^Cannot call method find\\(\\) on Symfony\\\\Component\\\\Console\\\\Application\\|null\\.$#"
count: 1
path: src/Command/ResetTestCommand.php
-
message: "#^Access to an undefined property SimpleXMLElement\\|false\\:\\:\\$file\\.$#"
count: 1

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[113],{2395:function(i,n,u){u(876)},876:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=2395,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[113],{2395:function(i,n,u){u(876)},876:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=2395,i(i.s=n)}]);

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

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -2,8 +2,8 @@
"entrypoints": {
"app": {
"js": [
"/build/runtime.74179306.js",
"/build/app.ea4d46bf.js"
"/build/runtime.6c399d29.js",
"/build/app.7719f352.js"
],
"css": [
"/build/app.899af573.css"
@@ -11,8 +11,8 @@
},
"app-rtl": {
"js": [
"/build/runtime.74179306.js",
"/build/app-rtl.6669505e.js"
"/build/runtime.6c399d29.js",
"/build/app-rtl.7a875ca7.js"
],
"css": [
"/build/app-rtl.bb694a34.css"
@@ -20,8 +20,8 @@
},
"export-pdf": {
"js": [
"/build/runtime.74179306.js",
"/build/export-pdf.32b1a2d8.js"
"/build/runtime.6c399d29.js",
"/build/export-pdf.395749ab.js"
],
"css": [
"/build/export-pdf.d8a6c23b.css"
@@ -29,8 +29,8 @@
},
"invoice": {
"js": [
"/build/runtime.74179306.js",
"/build/invoice.e9e8aa7d.js"
"/build/runtime.6c399d29.js",
"/build/invoice.773af9c4.js"
],
"css": [
"/build/invoice.595f2ed8.css"
@@ -38,8 +38,8 @@
},
"invoice-pdf": {
"js": [
"/build/runtime.74179306.js",
"/build/invoice-pdf.502e6e63.js"
"/build/runtime.6c399d29.js",
"/build/invoice-pdf.26d98626.js"
],
"css": [
"/build/invoice-pdf.2b749265.css"
@@ -47,14 +47,14 @@
},
"chart": {
"js": [
"/build/runtime.74179306.js",
"/build/chart.7e725b75.js"
"/build/runtime.6c399d29.js",
"/build/chart.62631acc.js"
]
},
"calendar": {
"js": [
"/build/runtime.74179306.js",
"/build/calendar.cf8275ae.js"
"/build/runtime.6c399d29.js",
"/build/calendar.7415ab21.js"
],
"css": [
"/build/calendar.d757753e.css"
@@ -62,8 +62,8 @@
},
"dashboard": {
"js": [
"/build/runtime.74179306.js",
"/build/dashboard.e3ce6fbb.js"
"/build/runtime.6c399d29.js",
"/build/dashboard.632f98fb.js"
],
"css": [
"/build/dashboard.b7129fa1.css"
@@ -71,21 +71,21 @@
}
},
"integrity": {
"/build/runtime.74179306.js": "sha384-OC1hTNUXUalKJcvmzrZ0TMCOIwnhxCxgG9dQkbcwR7WcBBCkl2H8bs3giiT2pAwG",
"/build/app.ea4d46bf.js": "sha384-PyuOwCnH7A+SwxmECJdtTOTEY/G5571SrCLJU1p2GDzgt5tSvSQAyFpvIMbSseI4",
"/build/runtime.6c399d29.js": "sha384-/rm616f12czi8l/27GvWXtb3g608vJZf2XTUKxqCRI4tsa2vUHP+BW90edTok5zC",
"/build/app.7719f352.js": "sha384-lj0mGChJMeCxDtjDy96KBKaW5E61RIqYc2+3RlVz+wcsIroUZxMApq0PsW8QcKFN",
"/build/app.899af573.css": "sha384-8FV7dixselI1s8FeZCs88+w6hVO9bJ7U1Ai12BBPE7O8bQOxqkhKsWHsCD+WCtdn",
"/build/app-rtl.6669505e.js": "sha384-k8BTJnF4xgczvXYu+nucr7wNwDw9v2cVYH6BNtwaoRJLVr0uhoTSzdyirqfjYwNU",
"/build/app-rtl.7a875ca7.js": "sha384-T7gLI61h9dGeMgzo63vKu4GiDOeLPct9zSUHrceNbhSwIdUmSSNoZ1+d7fKhJJ4/",
"/build/app-rtl.bb694a34.css": "sha384-0ANmqhe0IP4aUvWOWo/KZUgAqueE4hH/ZU0EREtgrtKXWM/JPMmRFBEXk8iZTEcd",
"/build/export-pdf.32b1a2d8.js": "sha384-ybmG79nEz8qi9KXvtgRaVmcOx0OQ05W5EPvHpHjRaOh23qlOF/dp89rVgoLuFw6o",
"/build/export-pdf.395749ab.js": "sha384-3Hjvmu4FC/0dhHnR8kyRBU7k2xMNy1lxBpGgOkrw8PxXnwyQDM8/5bQmkJbjVT1+",
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
"/build/invoice.e9e8aa7d.js": "sha384-JIXe1hyboSIC1ANrcga4w62hoZFpGzBMTzYjVenZ8+1NMXC0PXC/ZqsGiYh/uy0I",
"/build/invoice.773af9c4.js": "sha384-QmMqYJ0RP2WOYU7D4lLzKCBFDL6vCvZHQc7wf8K8N+hdCuTJwq1P0GuY81f30/SY",
"/build/invoice.595f2ed8.css": "sha384-pPD6gjc24k+qRscW+AS0trqN2MrBI7l0YbFvIjudaoOG0fWHuxpbGBP7P3E1er5a",
"/build/invoice-pdf.502e6e63.js": "sha384-rA+sITn2mkcoezrJYcY8j0kfp9kc9nadewwE4PMIfGwwK7m44HY9vCy1ZCA3Er2f",
"/build/invoice-pdf.26d98626.js": "sha384-gwNzQiU1y6qU/M9DPGiNW0MVZkLctEHk37sCES2X9ov+zugEaDABdkMjKBYOC9lz",
"/build/invoice-pdf.2b749265.css": "sha384-DXXgkz2WWnrWnfBnXX5fmfPQSPb98upMnWxYKwTGYS04EhrPIWfDCutB2unIrWh7",
"/build/chart.7e725b75.js": "sha384-dxi1x1S516fKFFrYP4w6XFqGHTurW8YBh7P5nt11amur+3B08JH0/yuyXNZvP8la",
"/build/calendar.cf8275ae.js": "sha384-opOQIFRD/XVjA2W1QVyoLeRuYHUf55RRYrZVEyYNKHs9VZzKFOTMBC/8PxBqQw+m",
"/build/chart.62631acc.js": "sha384-L4evSO0OZiQt+jTqfMR70M2Vid7Hl5YdPocC6syhSoBRavlf7Az9/Ldh4YJUuwAU",
"/build/calendar.7415ab21.js": "sha384-+iYr7VnMIxSQMERlaruX2Ktp6gWmGSyCxfUAaeSDkoninXdUdiKBjlcZZwhHhZWU",
"/build/calendar.d757753e.css": "sha384-cTmQMgHYjd2gfObFWmEUph7qQLCyXaIkneSf+bQ2mqVmZwqOB+pJOm/UYTyTjALJ",
"/build/dashboard.e3ce6fbb.js": "sha384-275eWBbQLvReq7BrXYcRgGnBrhki1xvdoqnwRVYGbD3S+BhUZEeez7aZ6XepdpcR",
"/build/dashboard.632f98fb.js": "sha384-PlHarP53f8b+47VZvbQw3LURA2vODFf7UMwpnktvukrhswaHtx93cx2M1BtO56JH",
"/build/dashboard.b7129fa1.css": "sha384-2nn5hLA+3YedgHYBpge62S8Losj8aoPwK9Zk9EvN1xEYatvOUQ7H3rIR2UUJAGOS"
}
}

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[872],{878:function(i,n,u){u(3385)},3385:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=878,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[872],{878:function(i,n,u){u(3385)},3385:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=878,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[117],{1555:function(i,n,u){u(6620)},6620:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=1555,i(i.s=n)}]);

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[117],{1555:function(i,n,u){u(6620)},6620:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=1555,i(i.s=n)}]);

View File

@@ -0,0 +1 @@
(self.webpackChunkkimai=self.webpackChunkkimai||[]).push([[896],{4820:function(i,n,u){u(3631)},3631:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=4820,i(i.s=n)}]);

View File

@@ -1 +0,0 @@
(self.webpackChunkkimai2=self.webpackChunkkimai2||[]).push([[896],{4820:function(i,n,u){u(3631)},3631:function(i,n,u){"use strict";u.r(n)}},function(i){var n;n=4820,i(i.s=n)}]);

View File

@@ -1,20 +1,20 @@
{
"build/app.css": "/build/app.899af573.css",
"build/app.js": "/build/app.ea4d46bf.js",
"build/app.js": "/build/app.7719f352.js",
"build/app-rtl.css": "/build/app-rtl.bb694a34.css",
"build/app-rtl.js": "/build/app-rtl.6669505e.js",
"build/app-rtl.js": "/build/app-rtl.7a875ca7.js",
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
"build/export-pdf.js": "/build/export-pdf.32b1a2d8.js",
"build/export-pdf.js": "/build/export-pdf.395749ab.js",
"build/invoice.css": "/build/invoice.595f2ed8.css",
"build/invoice.js": "/build/invoice.e9e8aa7d.js",
"build/invoice.js": "/build/invoice.773af9c4.js",
"build/invoice-pdf.css": "/build/invoice-pdf.2b749265.css",
"build/invoice-pdf.js": "/build/invoice-pdf.502e6e63.js",
"build/chart.js": "/build/chart.7e725b75.js",
"build/invoice-pdf.js": "/build/invoice-pdf.26d98626.js",
"build/chart.js": "/build/chart.62631acc.js",
"build/calendar.css": "/build/calendar.d757753e.css",
"build/calendar.js": "/build/calendar.cf8275ae.js",
"build/calendar.js": "/build/calendar.7415ab21.js",
"build/dashboard.css": "/build/dashboard.b7129fa1.css",
"build/dashboard.js": "/build/dashboard.e3ce6fbb.js",
"build/runtime.js": "/build/runtime.74179306.js",
"build/dashboard.js": "/build/dashboard.632f98fb.js",
"build/runtime.js": "/build/runtime.6c399d29.js",
"build/fonts/fa-solid-900.ttf": "/build/fonts/fa-solid-900.ad1782c7.ttf",
"build/fonts/fa-brands-400.ttf": "/build/fonts/fa-brands-400.26b80c88.ttf",
"build/fonts/fa-solid-900.woff2": "/build/fonts/fa-solid-900.83a538a0.woff2",

View File

@@ -1 +1 @@
!function(){"use strict";var e,r={},n={};function t(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,loaded:!1,exports:{}};return r[e].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}t.m=r,t.amdO={},e=[],t.O=function(r,n,o,i){if(!n){var u=1/0;for(l=0;l<e.length;l++){n=e[l][0],o=e[l][1],i=e[l][2];for(var f=!0,a=0;a<n.length;a++)(!1&i||u>=i)&&Object.keys(t.O).every((function(e){return t.O[e](n[a])}))?n.splice(a--,1):(f=!1,i<u&&(u=i));if(f){e.splice(l--,1);var c=o();void 0!==c&&(r=c)}}return r}i=i||0;for(var l=e.length;l>0&&e[l-1][2]>i;l--)e[l]=e[l-1];e[l]=[n,o,i]},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,{a:r}),r},t.d=function(e,r){for(var n in r)t.o(r,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e={121:0};t.O.j=function(r){return 0===e[r]};var r=function(r,n){var o,i,u=n[0],f=n[1],a=n[2],c=0;if(u.some((function(r){return 0!==e[r]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(a)var l=a(t)}for(r&&r(n);c<u.length;c++)i=u[c],t.o(e,i)&&e[i]&&e[i][0](),e[i]=0;return t.O(l)},n=self.webpackChunkkimai2=self.webpackChunkkimai2||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))}()}();
!function(){"use strict";var e,r={},n={};function t(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={id:e,loaded:!1,exports:{}};return r[e].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}t.m=r,t.amdO={},e=[],t.O=function(r,n,o,i){if(!n){var u=1/0;for(l=0;l<e.length;l++){n=e[l][0],o=e[l][1],i=e[l][2];for(var f=!0,a=0;a<n.length;a++)(!1&i||u>=i)&&Object.keys(t.O).every((function(e){return t.O[e](n[a])}))?n.splice(a--,1):(f=!1,i<u&&(u=i));if(f){e.splice(l--,1);var c=o();void 0!==c&&(r=c)}}return r}i=i||0;for(var l=e.length;l>0&&e[l-1][2]>i;l--)e[l]=e[l-1];e[l]=[n,o,i]},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,{a:r}),r},t.d=function(e,r){for(var n in r)t.o(r,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:r[n]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.hmd=function(e){return(e=Object.create(e)).children||(e.children=[]),Object.defineProperty(e,"exports",{enumerable:!0,set:function(){throw new Error("ES Modules may not assign module.exports or exports.*, Use ESM export syntax, instead: "+e.id)}}),e},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},function(){var e={121:0};t.O.j=function(r){return 0===e[r]};var r=function(r,n){var o,i,u=n[0],f=n[1],a=n[2],c=0;if(u.some((function(r){return 0!==e[r]}))){for(o in f)t.o(f,o)&&(t.m[o]=f[o]);if(a)var l=a(t)}for(r&&r(n);c<u.length;c++)i=u[c],t.o(e,i)&&e[i]&&e[i][0](),e[i]=0;return t.O(l)},n=self.webpackChunkkimai=self.webpackChunkkimai||[];n.forEach(r.bind(null,0)),n.push=r.bind(null,n.push.bind(n))}()}();

View File

@@ -108,7 +108,7 @@ abstract class AbstractResetCommand extends Command
{
try {
$command = $this->getApplication()->find('doctrine:schema:drop');
$command->run(new ArrayInput(['--force' => true]), $output);
$command->run(new ArrayInput(['--force' => true, '--full-database' => true]), $output);
} catch (Exception $ex) {
$io->error('Failed to drop database schema: ' . $ex->getMessage());

View File

@@ -18,13 +18,10 @@ use App\Entity\Team;
use App\Entity\User;
use App\Entity\UserPreference;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
/**
@@ -213,18 +210,4 @@ final class ResetTestCommand extends AbstractResetCommand
$this->entityManager->flush();
}
protected function dropSchema(SymfonyStyle $io, OutputInterface $output): int
{
try {
$command = $this->getApplication()->find('doctrine:schema:drop');
$command->run(new ArrayInput(['--force' => true, '--full-database' => true]), $output);
} catch (Exception $ex) {
$io->error('Failed to drop database schema: ' . $ex->getMessage());
return Command::FAILURE;
}
return Command::SUCCESS;
}
}

View File

@@ -12,16 +12,16 @@ namespace App;
/**
* Some "very" global constants for Kimai.
*/
class Constants
final class Constants
{
/**
* The current release version
*/
public const VERSION = '2.27.0';
public const VERSION = '2.28.0';
/**
* The current release: major * 10000 + minor * 100 + patch
*/
public const VERSION_ID = 22700;
public const VERSION_ID = 22800;
/**
* The software name
*/

View File

@@ -15,6 +15,7 @@ use App\Export\Package\SpoutSpreadsheet;
use App\Export\RendererInterface;
use App\Export\TimesheetExportInterface;
use App\Repository\Query\TimesheetQuery;
use OpenSpout\Writer\CSV\Options;
use OpenSpout\Writer\CSV\Writer;
use Symfony\Component\HttpFoundation\Response;
@@ -58,7 +59,10 @@ final class CsvRenderer implements RendererInterface, TimesheetExportInterface
throw new \Exception('Could not open temporary file');
}
$spreadsheet = new SpoutSpreadsheet(new Writer());
$options = new Options();
$options->SHOULD_ADD_BOM = false;
$spreadsheet = new SpoutSpreadsheet(new Writer($options));
$spreadsheet->open($filename);
$this->spreadsheetRenderer->writeSpreadsheet($spreadsheet, $exportItems, $query);

View File

@@ -144,6 +144,7 @@ final class PaginatedWorkingTimeChart extends AbstractWidget
return [
'begin' => clone $weekBegin,
'end' => clone $weekEnd,
'dateYear' => $year,
'thisMonth' => $thisMonth,
'lastWeekInYear' => $lastWeekInYear,
'lastWeekInLastYear' => $lastWeekInLastYear,

View File

@@ -10,8 +10,4 @@
<spacer size="16"></spacer>
<button class="large primary" href="{{ confirmationUrl }}">{{ 'registration.button'|trans({'%url%': confirmationUrl}, 'email') }}</button>
<spacer size="16"></spacer>
<p><small>{{ 'automated_email_dont_answer'|trans({}, 'email') }}</small></p>
{% endblock %}

View File

@@ -6,8 +6,4 @@
{% block body %}
<p>{{ body|trans({}, 'email') }}<p>
<spacer size="16"></spacer>
<p><small>{{ 'automated_email_dont_answer'|trans({}, 'email') }}</small></p>
{% endblock %}

View File

@@ -10,6 +10,6 @@
<spacer size="32"></spacer>
<p><small>{{ 'automated_email_dont_answer'|trans({}, 'email') }}</small></p>
{% block no_answer %}<p><small>{{ 'automated_email_dont_answer'|trans({}, 'email') }}</small></p>{% endblock %}
{% endapply %}

View File

@@ -60,7 +60,7 @@
<div class="col-sm-3 col-xs-6 mt-1 mb-2 mb-md-0">
<div class="text-center">
<h5 class="mb-1">{{ data.year|duration }}</h5>
<span>{{ 'stats.workingTimeYear'|trans({'%year%': data.thisMonth|date_format('Y')}) }}</span>
<span>{{ 'stats.workingTimeYear'|trans({'%year%': data.dateYear}) }}</span>
</div>
</div>
{% endif %}

View File

@@ -24,9 +24,6 @@ use PHPUnit\Framework\TestCase;
*/
class PaginatedWorkingTimeChartTest extends TestCase
{
/**
* @return PaginatedWorkingTimeChart
*/
public function createSut(): PaginatedWorkingTimeChart
{
$repository = $this->createMock(TimesheetRepository::class);
@@ -73,7 +70,7 @@ class PaginatedWorkingTimeChartTest extends TestCase
$repository = $this->createMock(TimesheetRepository::class);
$expectedKeys = [
'begin', 'end', 'thisMonth', 'lastWeekInYear', 'lastWeekInLastYear', 'day', 'week', 'month', 'year', 'financial', 'financialBegin'
'begin', 'end', 'dateYear', 'thisMonth', 'lastWeekInYear', 'lastWeekInLastYear', 'day', 'week', 'month', 'year', 'financial', 'financialBegin'
];
$configuration = SystemConfigurationFactory::createStub(['company' => ['financial_year' => null]]);
@@ -101,7 +98,7 @@ class PaginatedWorkingTimeChartTest extends TestCase
$repository = $this->createMock(TimesheetRepository::class);
$expectedKeys = [
'begin', 'end', 'thisMonth', 'lastWeekInYear', 'lastWeekInLastYear', 'day', 'week', 'month', 'year', 'financial', 'financialBegin'
'begin', 'end', 'dateYear', 'thisMonth', 'lastWeekInYear', 'lastWeekInLastYear', 'day', 'week', 'month', 'year', 'financial', 'financialBegin'
];
$configuration = SystemConfigurationFactory::createStub(['company' => ['financial_year' => '2020-01-01']]);

View File

@@ -4217,9 +4217,9 @@ __metadata:
languageName: node
linkType: hard
"kimai2@workspace:.":
"kimai@workspace:.":
version: 0.0.0-use.local
resolution: "kimai2@workspace:."
resolution: "kimai@workspace:."
dependencies:
"@babel/core": "npm:^7"
"@babel/eslint-parser": "npm:^7"