Release 2.0.10 (#3927)
* allow API calls via GET * allow to stop timesheet via GET * improve form handling and validation * improve stop button handling * bump version
This commit is contained in:
@@ -85,20 +85,20 @@ export default class KimaiAPILink extends KimaiPlugin {
|
||||
API.handleError(message, error);
|
||||
};
|
||||
|
||||
let data = {};
|
||||
if (attributes['payload'] !== undefined) {
|
||||
data = attributes['payload'];
|
||||
}
|
||||
|
||||
if (method === 'PATCH') {
|
||||
let data = {};
|
||||
if (attributes['payload'] !== undefined) {
|
||||
data = attributes['payload'];
|
||||
}
|
||||
API.patch(url, data, successHandle, errorHandle);
|
||||
} else if (method === 'POST') {
|
||||
let data = {};
|
||||
if (attributes['payload'] !== undefined) {
|
||||
data = attributes['payload'];
|
||||
}
|
||||
API.post(url, data, successHandle, errorHandle);
|
||||
} else if (method === 'DELETE') {
|
||||
API.delete(url, successHandle, errorHandle);
|
||||
} else if (method === 'GET') {
|
||||
API.get(url, data, successHandle, errorHandle);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapts the ticktac menus accordingg to the given entries (amount and duration).
|
||||
* Adapts the ticktac menus according to the given entries (amount and duration).
|
||||
* Does not influence listing pages, as those refresh themselves.
|
||||
*
|
||||
* @param {array} entries
|
||||
@@ -168,7 +168,7 @@ export default class KimaiActiveRecords extends KimaiPlugin {
|
||||
for (let link of allReplacer) {
|
||||
const replacerName = link.dataset['replacer'];
|
||||
if (replacerName === 'url') {
|
||||
link.href = node.dataset['href'].replace('000', timesheet.id);
|
||||
link.dataset['href'] = node.dataset['href'].replace('000', timesheet.id);
|
||||
} else if (replacerName === 'activity') {
|
||||
link.innerText = timesheet.activity.name;
|
||||
} else if (replacerName === 'project') {
|
||||
|
||||
40
phpstan.neon
40
phpstan.neon
@@ -140,26 +140,11 @@ parameters:
|
||||
count: 1
|
||||
path: src/API/TagController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$activity of method App\\\\Entity\\\\Timesheet\\:\\:setActivity\\(\\) expects App\\\\Entity\\\\Activity, App\\\\Entity\\\\Activity\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/API/TimesheetController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$datetime of method App\\\\Timesheet\\\\DateTimeFactory\\:\\:createDateTime\\(\\) expects string, mixed given\\.$#"
|
||||
count: 3
|
||||
path: src/API/TimesheetController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$description of method App\\\\Entity\\\\Timesheet\\:\\:setDescription\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/API/TimesheetController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$project of method App\\\\Entity\\\\Timesheet\\:\\:setProject\\(\\) expects App\\\\Entity\\\\Project, App\\\\Entity\\\\Project\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/API/TimesheetController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$user of class App\\\\Event\\\\RecentActivityEvent constructor expects App\\\\Entity\\\\User, App\\\\Entity\\\\User\\|null given\\.$#"
|
||||
count: 1
|
||||
@@ -1250,16 +1235,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/QuickEntryController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$activity of method App\\\\Entity\\\\Timesheet\\:\\:setActivity\\(\\) expects App\\\\Entity\\\\Activity, App\\\\Entity\\\\Activity\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/QuickEntryController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$project of method App\\\\Entity\\\\Timesheet\\:\\:setProject\\(\\) expects App\\\\Entity\\\\Project, App\\\\Entity\\\\Project\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/QuickEntryController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\Reporting\\\\AbstractUserReportController\\:\\:getStatisticDataRaw\\(\\) return type has no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
@@ -1745,11 +1720,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Controller/TimesheetTeamController.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$user of method App\\\\Entity\\\\Timesheet\\:\\:setUser\\(\\) expects App\\\\Entity\\\\User, mixed given\\.$#"
|
||||
count: 1
|
||||
path: src/Controller/TimesheetTeamController.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Controller\\\\UserController\\:\\:exportAction\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
@@ -1860,11 +1830,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/DataFixtures/TimesheetFixtures.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$description of method App\\\\Entity\\\\Timesheet\\:\\:setDescription\\(\\) expects string, string\\|null given\\.$#"
|
||||
count: 1
|
||||
path: src/DataFixtures/TimesheetFixtures.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$user of method App\\\\DataFixtures\\\\TimesheetFixtures\\:\\:createTimesheetEntry\\(\\) expects App\\\\Entity\\\\User, App\\\\Entity\\\\User\\|null given\\.$#"
|
||||
count: 2
|
||||
@@ -4880,11 +4845,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Form/Type/QuickEntryWeekType.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$user of method App\\\\Entity\\\\Timesheet\\:\\:setUser\\(\\) expects App\\\\Entity\\\\User, mixed given\\.$#"
|
||||
count: 1
|
||||
path: src/Form/Type/QuickEntryWeekType.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Form\\\\Type\\\\SearchTermType\\:\\:buildForm\\(\\) has parameter \\$options with no value type specified in iterable type array\\.$#"
|
||||
count: 1
|
||||
|
||||
2
public/build/app.454ad090.js
Normal file
2
public/build/app.454ad090.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,7 +3,7 @@
|
||||
"app": {
|
||||
"js": [
|
||||
"/build/runtime.f0079159.js",
|
||||
"/build/app.bd3fd9c1.js"
|
||||
"/build/app.454ad090.js"
|
||||
],
|
||||
"css": [
|
||||
"/build/app.c429ff5b.css"
|
||||
@@ -63,7 +63,7 @@
|
||||
},
|
||||
"integrity": {
|
||||
"/build/runtime.f0079159.js": "sha384-H22sAW1aTvyIPqvHOvGXWSWTxf0y6mptp+MsVmyXCfjx/WJjBbhX9gbUZ+qIuihV",
|
||||
"/build/app.bd3fd9c1.js": "sha384-lz7W4QdKZkFcM0r1sScURXhxrv/ezU2DXgjGgubQsorHuaQDcKKoucOvSK3yxW/U",
|
||||
"/build/app.454ad090.js": "sha384-5EqTkHqGv38S0Z8pXK2h0tHtGoCxbBkAYeSg1S0pe5eTWItPP4fiIfgJkD6eVH9U",
|
||||
"/build/app.c429ff5b.css": "sha384-m7RJ9g2fW3tENrf+oi/FsH8wTu6fsjuhvpDztfqr+YjNN0AvCapER6yvmGkqwp+I",
|
||||
"/build/export-pdf.587575e7.js": "sha384-J50GStmmfVwUTN4dIRQ02eg9hyzGFPSzpTtpPody92j0V6zCqw+s5l8+ZhVTugeW",
|
||||
"/build/export-pdf.d8a6c23b.css": "sha384-ztepocHE4rnGE9eKZ4kL6jTKaePUyiwiB9TjJjstjpf/ckcKg1HedrEOOk/8ElJg",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"build/app.css": "/build/app.c429ff5b.css",
|
||||
"build/app.js": "/build/app.bd3fd9c1.js",
|
||||
"build/app.js": "/build/app.454ad090.js",
|
||||
"build/export-pdf.css": "/build/export-pdf.d8a6c23b.css",
|
||||
"build/export-pdf.js": "/build/export-pdf.587575e7.js",
|
||||
"build/invoice.css": "/build/invoice.3c80ee80.css",
|
||||
|
||||
@@ -106,6 +106,7 @@ final class TimesheetController extends BaseApiController
|
||||
if ('all' === $userId) {
|
||||
$query->setUser(null);
|
||||
} else {
|
||||
/** @var User|null $user */
|
||||
$user = $userRepository->find($userId);
|
||||
if ($user === null) {
|
||||
throw $this->createNotFoundException('Unknown user: ' . $userId);
|
||||
@@ -447,11 +448,15 @@ final class TimesheetController extends BaseApiController
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops an active timesheet record
|
||||
* Stops an active timesheet record.
|
||||
*
|
||||
* This route is available via GET and PATCH, as users over and over again run into errors when stopping.
|
||||
* Likely caused by a slow JS engine and a fast-click after page reload.
|
||||
*/
|
||||
#[IsGranted('stop', 'timesheet')]
|
||||
#[OA\Response(response: 200, description: 'Stops an active timesheet record and returns it afterwards.', content: new OA\JsonContent(ref: '#/components/schemas/TimesheetEntity'))]
|
||||
#[OA\Parameter(name: 'id', in: 'path', description: 'Timesheet record ID to stop', required: true)]
|
||||
#[Rest\Get(path: '/{id}/stop', name: 'stop_timesheet_get', requirements: ['id' => '\d+'])]
|
||||
#[Rest\Patch(path: '/{id}/stop', name: 'stop_timesheet', requirements: ['id' => '\d+'])]
|
||||
#[ApiSecurity(name: 'apiUser')]
|
||||
#[ApiSecurity(name: 'apiToken')]
|
||||
|
||||
@@ -17,11 +17,11 @@ class Constants
|
||||
/**
|
||||
* The current release version
|
||||
*/
|
||||
public const VERSION = '2.0.9';
|
||||
public const VERSION = '2.0.10';
|
||||
/**
|
||||
* The current release: major * 10000 + minor * 100 + patch
|
||||
*/
|
||||
public const VERSION_ID = 20009;
|
||||
public const VERSION_ID = 20010;
|
||||
/**
|
||||
* The software name
|
||||
*/
|
||||
|
||||
@@ -88,6 +88,7 @@ final class TimesheetTeamController extends TimesheetAbstractController
|
||||
/** @var ArrayCollection<Team> $teams */
|
||||
$teams = $createForm->get('teams')->getData();
|
||||
|
||||
/** @var array<User> $allUsers */
|
||||
$allUsers = $users->toArray();
|
||||
/** @var Team $team */
|
||||
foreach ($teams as $team) {
|
||||
|
||||
@@ -337,11 +337,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setUser(User $user): Timesheet
|
||||
public function setUser(?User $user): Timesheet
|
||||
{
|
||||
$this->user = $user;
|
||||
|
||||
@@ -353,11 +349,7 @@ class Timesheet implements EntityWithMetaFields, ExportableItem
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Activity $activity
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setActivity($activity): Timesheet
|
||||
public function setActivity(?Activity $activity): Timesheet
|
||||
{
|
||||
$this->activity = $activity;
|
||||
|
||||
@@ -374,22 +366,14 @@ class Timesheet implements EntityWithMetaFields, ExportableItem
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Project $project
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setProject(Project $project): Timesheet
|
||||
public function setProject(?Project $project): Timesheet
|
||||
{
|
||||
$this->project = $project;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $description
|
||||
* @return Timesheet
|
||||
*/
|
||||
public function setDescription($description): Timesheet
|
||||
public function setDescription(?string $description): Timesheet
|
||||
{
|
||||
$this->description = $description;
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use App\Entity\User;
|
||||
use App\Model\QuickEntryModel;
|
||||
use App\Validator\Constraints\QuickEntryTimesheet;
|
||||
use DateTime;
|
||||
@@ -129,8 +130,12 @@ final class QuickEntryWeekType extends AbstractType
|
||||
return $transformValue;
|
||||
}
|
||||
|
||||
$user = $transformValue->getUser();
|
||||
if ($user === null && $options['user'] instanceof User) {
|
||||
$user = $options['user'];
|
||||
}
|
||||
foreach ($transformValue->getTimesheets() as $timesheet) {
|
||||
$timesheet->setUser($transformValue->getUser() ?? $options['user']);
|
||||
$timesheet->setUser($user);
|
||||
$timesheet->setProject($project);
|
||||
$timesheet->setActivity($activity);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
{% endif %}
|
||||
{% set entry = active_timesheets[0] %}
|
||||
<div class="ticktac-menu" data-api="{{ path('active_timesheet') }}" data-href="{{ path('stop_timesheet', {'id' : '000'}) }}" style="{% if not hasActiveRecords %}display:none{% endif %}">
|
||||
<a data-replacer="url" class="api-link ticktac-running ticktac-stop btn {{ class }} btn-icon px-sm-2" href="{{ path('stop_timesheet', {'id' : entry.id}) }}" data-event="kimai.timesheetStop kimai.timesheetUpdate" data-method="PATCH" data-msg-error="timesheet.stop.error" data-msg-success="timesheet.stop.success"{% if hasActiveRecords %} accesskey="s"{% endif %}>
|
||||
<a data-replacer="url" class="api-link ticktac-running ticktac-stop btn {{ class }} btn-icon px-sm-2" href="#" data-href="{{ path('stop_timesheet', {'id' : entry.id}) }}" data-event="kimai.timesheetStop kimai.timesheetUpdate" data-method="PATCH" data-msg-error="timesheet.stop.error" data-msg-success="timesheet.stop.success"{% if hasActiveRecords %} accesskey="s"{% endif %}>
|
||||
<i class="text-red {{ 'stop-small'|icon(false) }} me-0 me-sm-1"></i>
|
||||
<span class="d-none d-sm-block" data-replacer="duration" data-title="true" data-since="{{ entry.begin is null ? '' : entry.begin|date_format(constant('DATE_ISO8601')) }}">{{ entry is iterable ? 0|duration : entry|duration }}</span>
|
||||
</a>
|
||||
|
||||
@@ -1687,21 +1687,11 @@ parameters:
|
||||
count: 1
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$activity of method App\\\\Entity\\\\Timesheet\\:\\:setActivity\\(\\) expects App\\\\Entity\\\\Activity, App\\\\Entity\\\\Activity\\|null given\\.$#"
|
||||
count: 1
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$json of function json_decode expects string, string\\|false given\\.$#"
|
||||
count: 32
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$project of method App\\\\Entity\\\\Timesheet\\:\\:setProject\\(\\) expects App\\\\Entity\\\\Project, App\\\\Entity\\\\Project\\|null given\\.$#"
|
||||
count: 1
|
||||
path: API/TimesheetControllerTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, mixed given\\.$#"
|
||||
count: 1
|
||||
@@ -9007,16 +8997,6 @@ parameters:
|
||||
count: 1
|
||||
path: Repository/TimesheetRepositoryTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$activity of method App\\\\Entity\\\\Timesheet\\:\\:setActivity\\(\\) expects App\\\\Entity\\\\Activity, App\\\\Entity\\\\Activity\\|null given\\.$#"
|
||||
count: 2
|
||||
path: Repository/TimesheetRepositoryTest.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$project of method App\\\\Entity\\\\Timesheet\\:\\:setProject\\(\\) expects App\\\\Entity\\\\Project, App\\\\Entity\\\\Project\\|null given\\.$#"
|
||||
count: 2
|
||||
path: Repository/TimesheetRepositoryTest.php
|
||||
|
||||
-
|
||||
message: "#^Method App\\\\Tests\\\\Saml\\\\SamlBadgeTest\\:\\:testConstruct\\(\\) has no return type specified\\.$#"
|
||||
count: 1
|
||||
|
||||
Reference in New Issue
Block a user