Skip to content
This repository was archived by the owner on Oct 22, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
aa478a5
#5418 Change order in timesheets menu
harismacic1 Jan 15, 2026
f260710
[#5418] Remove overflow
harismacic1 Jan 15, 2026
0e0aeff
#5418 Set bigger width
harismacic1 Jan 15, 2026
5f38236
#5562 Resize description window
harismacic1 Jan 16, 2026
dfc4f70
#5424 Add jquery call to track ticket description change
harismacic1 Jan 8, 2026
8dfbd00
#5424 Track old and new text in description change, implement summari…
harismacic1 Jan 16, 2026
c1cba38
#5598 Track current profile and change it dynamically when switching …
harismacic1 Jan 19, 2026
7d70dbb
#5560 Remove non-readable variable from CSV
harismacic1 Jan 19, 2026
d366004
[#5498] Add adequate info text on hover
harismacic1 Jan 19, 2026
207dd88
#5498 Format new part of the code
harismacic1 Jan 19, 2026
560035f
#5498 Remove unecessary arrow from week view label
harismacic1 Jan 19, 2026
d95fbba
[#5498] Center info icon
harismacic1 Jan 19, 2026
48ef59b
#5498 Add info label to monthly view
harismacic1 Jan 20, 2026
da66a3d
#5602 Register history log when clicking assign to me
harismacic1 Jan 20, 2026
94745cd
#5602 Remove console logs
harismacic1 Jan 20, 2026
d315091
[#5602] Remove unnecessary empty lines
harismacic1 Jan 20, 2026
56e81fc
#5597 Write autofilter on client change
harismacic1 Jan 19, 2026
947a4d9
#5597 Add changes tracker in Project filter
harismacic1 Jan 20, 2026
00488f5
#5597 Add jquery listeners on all filters
harismacic1 Jan 20, 2026
4c749cf
#5597 Format part of the code
harismacic1 Jan 20, 2026
66be6ef
Revert "[#5602] Remove unnecessary empty lines"
harismacic1 Jan 20, 2026
da7c18e
Revert "#5602 Remove console logs"
harismacic1 Jan 20, 2026
8252a11
Revert "#5602 Register history log when clicking assign to me"
harismacic1 Jan 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions app/Domain/Tickets/Controllers/TicketHistoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public function logStatusChange(): JsonResponse
{
if (!$this->authService->loggedIn()) {
return new JsonResponse([
'success' => false,
'success' => false,
'error' => 'Unauthorized'
], 401);
}
Expand All @@ -44,7 +44,7 @@ public function logStatusChange(): JsonResponse

if (!$ticketId) {
return new JsonResponse([
'success' => false,
'success' => false,
'error' => 'No ticket ID provided'
], 400);
}
Expand All @@ -68,7 +68,7 @@ public function logStatusChange(): JsonResponse
]);
} else {
return new JsonResponse([
'success' => false,
'success' => false,
'error' => 'Failed to save status change'
], 500);
}
Expand Down Expand Up @@ -101,32 +101,50 @@ public function getStatusChanges(): Response
$html = '<ul style="list-style: none; padding: 0; margin: 0;">';
foreach ($changes as $change) {
$detailsAttributeId = $change['detailsAttributeId'];
if($detailsAttributeId === 'priority') {
$attributeLabel = 'Priority';
} elseif($detailsAttributeId === 'storypoints') {
$attributeLabel = 'Effort';
} elseif($detailsAttributeId === 'editorId') {
$attributeLabel = 'Assigned to';
} elseif($detailsAttributeId === 'deadline') {
$attributeLabel = 'Due Date';
} elseif($detailsAttributeId === 'dueTime') {
$attributeLabel = 'Due Date Time';
} else {
$attributeLabel = 'Status';
}

$attributeLabels = [
'priority' => 'Priority',
'storypoints' => 'Effort',
'editorId' => 'Assigned to',
'deadline' => 'Due Date',
'dueTime' => 'Due Date Time',
'ticketDescription' => 'Description',
];

$attributeLabel = $attributeLabels[$detailsAttributeId] ?? 'Status';

$html .= '<li style="padding: 8px 0; border-bottom: 1px solid #eee;">';
$html .= '<strong>' . htmlspecialchars($change['changedBy']) . '</strong> changed '. $attributeLabel . ' on ';
$html .= '<strong>' . htmlspecialchars($change['changedBy']) . '</strong> changed ' . $attributeLabel . ' on ';
$html .= '<span style="color: #666; font-size: 0.9em;">' . date('d.m.Y H:i', strtotime($change['changedAt'])) . '</span><br>';
$html .= '<span style="color: #999;">' . htmlspecialchars($change['oldStatusText']) . '</span>';
$html .= ' <i class="fa fa-arrow-right" style="color: #999; font-size: 0.8em;"></i> ';
$html .= '<span style="color: #28a745; font-weight: bold;">' . htmlspecialchars($change['newStatusText']) . '</span>';

if ($detailsAttributeId === 'ticketDescription') {
$html .= '<div style="margin-top: 8px;">';
$html .= '<details style="cursor: pointer;">';
$html .= '<summary style="color: #666; font-size: 0.9em;">View changes</summary>';
$html .= '<div style="margin-top: 8px; padding: 8px; background: #f5f5f5; border-radius: 4px;">';
$html .= '<div style="margin-bottom: 8px;"><strong>Old:</strong></div>';
$html .= '<div style="padding: 8px; background: #fff; border-left: 3px solid #dc3545; margin-bottom: 12px;">';
$html .= $change['oldStatusText'] ?: '<em>Empty</em>';
$html .= '</div>';
$html .= '<div style="margin-bottom: 8px;"><strong>New:</strong></div>';
$html .= '<div style="padding: 8px; background: #fff; border-left: 3px solid #28a745;">';
$html .= $change['newStatusText'] ?: '<em>Empty</em>';
$html .= '</div>';
$html .= '</div>';
$html .= '</details>';
$html .= '</div>';
} else {
$html .= '<span style="color: #999;">' . htmlspecialchars($change['oldStatusText']) . '</span>';
$html .= ' <i class="fa fa-arrow-right" style="color: #999; font-size: 0.8em;"></i> ';
$html .= '<span style="color: #28a745; font-weight: bold;">' . htmlspecialchars($change['newStatusText']) . '</span>';
}

$html .= '</li>';
}
$html .= '</ul>';
}

return new Response($html, 200, ['Content-Type' => 'text/html']);

} catch (\Exception $e) {
return new Response(
'<p style="color: red;">Error loading status changes: ' . htmlspecialchars($e->getMessage()) . '</p>',
Expand Down
43 changes: 43 additions & 0 deletions app/Domain/Tickets/Templates/submodules/ticketDetails.sub.php
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,49 @@ function loadStatusHistory(ticketId) {
const ticketIdOnLoad = $('#status-change-log').data('ticket-id');
if (ticketIdOnLoad) {
loadStatusHistory(ticketIdOnLoad);
}
window.initialTicketDescription = '';

if (typeof tinymce !== 'undefined') {
tinymce.on('AddEditor', function(e) {
if (e.editor.id === 'ticketDescription') {
e.editor.on('init', function() {
window.initialTicketDescription = e.editor.getContent();
});

e.editor.off('SaveContent');

e.editor.on('SaveContent', function() {
const currentDescription = e.editor.getContent();

if (window.initialTicketDescription !== currentDescription) {
const ticketId = $('#status-change-log').data('ticket-id');
const user = $('#status-select').data('user') || 'Unknown User';

$.ajax({
url: '<?= BASE_URL ?>/tickets/ticketHistoryController/logStatusChange',
method: 'POST',
data: {
ticketId: ticketId,
oldStatus: '',
newStatus: '',
oldStatusText: window.initialTicketDescription,
newStatusText: currentDescription,
user: user,
detailsAttributeId: 'ticketDescription'
},
success: function(response) {
window.initialTicketDescription = currentDescription;
loadStatusHistory(ticketId);
},
error: function(xhr, status, error) {
console.error('Error logging description:', error);
}
});
}
});
}
});
}

$('#status-select, #priority, #storypoints, #editorId, #deadline').on('change', function() {
Expand Down
2 changes: 1 addition & 1 deletion app/Domain/Tickets/Templates/submodules/timesheet.sub.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
</span>
<label for="description"><?php echo $tpl->__('label.description') ?></label>
<span class="field">
<textarea rows="5" cols="50" id="description" name="description"><?php echo $values['description']; ?></textarea><br />
<textarea rows="5" cols="50" id="description" name="description" style="width:600px; height:250px;"><?php echo $values['description']; ?></textarea><br />
</span>
<input type="hidden" name="saveTimes" value="1" />
<input type="submit" value="<?php echo $tpl->__('buttons.save'); ?>" name="saveTimes" class="button" />
Expand Down
12 changes: 6 additions & 6 deletions app/Domain/Timesheets/Repositories/Timesheets.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
private DbCore $db;

public array $kind = [
'GENERAL_BILLABLE' => 'label.general_billable',
'GENERAL_NOT_BILLABLE' => 'label.general_not_billable',
'PROJECTMANAGEMENT' => 'label.projectmanagement',
'DEVELOPMENT' => 'label.development',
'BUGFIXING_NOT_BILLABLE' => 'label.bugfixing_not_billable',
'TESTING' => 'label.testing',
'GENERAL_BILLABLE' => 'General, billable',
'GENERAL_NOT_BILLABLE' => 'General, not billable',
'PROJECTMANAGEMENT' => 'Project management',
'DEVELOPMENT' => 'Development',
'BUGFIXING_NOT_BILLABLE' => 'Bugfixing, not billable',
'TESTING' => 'Testing',
];

/**
Expand Down Expand Up @@ -777,7 +777,7 @@
$formattedDate = $workDate->setTimezone('CEST')->format('Y-m-d H:i:s');


$call->bindValue(':workDate', $formattedDate);

Check failure on line 780 in app/Domain/Timesheets/Repositories/Timesheets.php

View workflow job for this annotation

GitHub Actions / phpstan

Undefined variable: $call

$query = "INSERT INTO `zp_timesheets` (userId, ticketId, workDate, hours, kind, modified)
VALUES (:sessionId, :ticketId, :workDate, :hoursWorked, 'GENERAL_BILLABLE', :modified)
Expand Down
13 changes: 10 additions & 3 deletions app/Domain/Timesheets/Templates/showAll.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ function updateProjectCountInline() {
<tr>
<td style="vertical-align: top;">
<label for="clients"><?php echo $tpl->__('label.client'); ?></label>
<select name="clientId">
<select name="clientId" id ="clients">
<option value="-1"><?php echo strip_tags($tpl->__('menu.all_clients')) ?></option>
<?php foreach ($tpl->get('allClients') as $client) {?>
<option value="<?= $client['id'] ?>"
Expand Down Expand Up @@ -239,7 +239,7 @@ function updateProjectCountInline() {
<div id="projectCheckboxDropdown" class="project-checkbox-dropdown" style="display: none; position: absolute; z-index: 1000; background: white; border: 1px solid #d0d5dd; border-radius: 14px; width: 100%; max-height: 250px; overflow-y: auto; box-shadow: 0 8px 20px rgba(15, 23, 42, 0.1); margin-top: 6px;">
<label style="display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-bottom: 1px solid #eef2f7; background: #f7f9fc; font-weight: bold; border-top-left-radius: 14px; border-top-right-radius: 14px; cursor: pointer;" onclick="event.stopPropagation();">
<input type="checkbox" name="project[]" value="-1" class="project-checkbox-all" id="projectCheckboxAll" style="margin: 0; vertical-align: middle;"
onchange="if(this.checked) { document.querySelectorAll('.project-checkbox').forEach(function(cb){cb.checked=false;}); } updateProjectCountInline();"
onchange="if(this.checked) { document.querySelectorAll('.project-checkbox').forEach(function(cb){cb.checked=false;}); } updateProjectCountInline(); document.getElementById('form').submit();"
<?php if (!is_array($tpl->get('projectFilter')) || $tpl->get('projectFilter') == -1) {
echo 'checked="checked"';
} ?>>
Expand All @@ -251,7 +251,7 @@ function updateProjectCountInline() {
foreach ($tpl->get('allProjects') as $project) { ?>
<label style="display: flex; align-items: center; gap: 8px; padding: 10px 12px; cursor: pointer; color: #333; transition: background-color 0.2s ease;" class="project-checkbox-label" onmouseover="this.style.background='#eef2f7'; this.style.color='#333';" onmouseout="this.style.background='white'; this.style.color='#333';" onclick="event.stopPropagation();">
<input type="checkbox" name="project[]" value="<?= $project['id'] ?>" class="project-checkbox" style="margin: 0; vertical-align: middle;"
onchange="if(this.checked) { document.getElementById('projectCheckboxAll').checked=false; } else { var anyChecked = document.querySelectorAll('.project-checkbox:checked').length > 0; if(!anyChecked) { document.getElementById('projectCheckboxAll').checked=true; } } updateProjectCountInline();"
onchange="if(this.checked) { document.getElementById('projectCheckboxAll').checked=false; } else { var anyChecked = document.querySelectorAll('.project-checkbox:checked').length > 0; if(!anyChecked) { document.getElementById('projectCheckboxAll').checked=true; } } updateProjectCountInline(); document.getElementById('form').submit();"
<?php if (is_array($selectedProjects) && in_array($project['id'], $selectedProjects)) {
echo 'checked="checked"';
} ?>>
Expand Down Expand Up @@ -511,3 +511,10 @@ function updateProjectCountInline() {
</form>
</div>
</div>
<script>
jQuery(document).ready(function() {
jQuery('#clients, #userId, #kind').on('change', function() {
jQuery('input.reload[type="submit"]').trigger('click');
});
});
</script>
44 changes: 36 additions & 8 deletions app/Domain/Timesheets/Templates/showMy.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,51 @@
<!-- page header -->

<div class="maincontent">
<div class="maincontentinner">
<div class="maincontentinner" style ="width:1200px;">
<?php
echo $tpl->displayNotification();

?>

<form action="<?php echo BASE_URL ?>/timesheets/showMy" method="post" id="timesheetList">
<div class="btn-group viewDropDown pull-right">
<div style="position: relative; display: inline-block;">
<button style="cursor: pointer; background: none; border: none; font-size: 18px;margin-top:5px;">
&#x24D8;
<span style="
visibility: hidden;
opacity: 0;
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
background-color: #333;
color: white;
padding: 8px 12px;
border-radius: 6px;
white-space: nowrap;
font-size: 14px;
transition: opacity 0.3s, visibility 0.3s;
z-index: 1000;
">
You can export your timesheet in the <strong>List view</strong>.
</span>
</button>
</div>

<style>
button:hover span {
visibility: visible !important;
opacity: 1 !important;
}
</style>
<button class="btn dropdown-toggle" data-toggle="dropdown">
<?php echo $tpl->__('links.week_view') ?> <?= $tpl->__('links.view') ?>
</button>
<ul class="dropdown-menu">
<li><a href="<?php echo BASE_URL ?>/timesheets/showMy" class="active"><?php echo $tpl->__('links.week_view') ?></a></li>
<li><a href="<?php echo BASE_URL ?>/timesheets/showMyList" ><?php echo $tpl->__('links.list_view') ?></a></li>
<li><a href="<?= BASE_URL?>/timesheets/showMyMonthlyTimesheet"><i class="fa fa-calendar-alt" style="margin-right:5px;"></i>Monthly View</a></li>
<li><a href="<?php echo BASE_URL ?>/timesheets/showMyList" ><?php echo $tpl->__('links.list_view') ?></a></li>
</ul>
</div>
<div class="pull-left" style="padding-left:5px; margin-top:-3px;">
Expand All @@ -245,7 +275,7 @@
</div>

</div>
<div style=" width: 100%; overflow-x:scroll;">
<div style=" width: 100%;">
<table cellpadding="0" width="100%" class="table table-bordered display timesheetTable" id="dyntableX" data-hours-format="<?= $tpl->escape($hoursFormat); ?>">
<colgroup>
<col class="con0" >
Expand Down Expand Up @@ -392,12 +422,10 @@ class="hourCell"
<?php } ?>

<!-- Row to add new time registration -->
<tr class="gradeA timesheetRow">
<td width="5%">-</td>
<td width="5%">-</td>
<td width="12%">
<tr class="gradeA timesheetRow" style="z-index: 9999;" >
<td width="14%" style="z-index: 9999;" >
<div class="form-group" id="projectSelect">
<select data-placeholder="<?php echo $tpl->__('input.placeholders.choose_project')?>" style="" class="project-select" >
<select data-placeholder="<?php echo $tpl->__('input.placeholders.choose_project')?>" class="project-select">
<option value=""></option>
<?php foreach ($tpl->get('allProjects') as $projectRow) { ?>
<?php echo sprintf(
Expand Down
2 changes: 1 addition & 1 deletion app/Domain/Timesheets/Templates/showMyList.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ class="dateTo"
<button class="btn dropdown-toggle" data-toggle="dropdown"><?= $tpl->__('links.list_view') ?> <?= $tpl->__('links.view') ?></button>
<ul class="dropdown-menu">
<li><a href="<?= BASE_URL?>/timesheets/showMy" ><?= $tpl->__('links.week_view') ?></a></li>
<li><a href="<?= BASE_URL?>/timesheets/showMyList" class="active"><?= $tpl->__('links.list_view') ?></a></li>
<li><a href="<?= BASE_URL?>/timesheets/showMyMonthlyTimesheet"><i class="fa fa-calendar-alt" style="margin-right:5px;"></i>Monthly View</a></li>
<li><a href="<?= BASE_URL?>/timesheets/showMyList" class="active"><?= $tpl->__('links.list_view') ?></a></li>
</ul>
</div>
</div>
Expand Down
32 changes: 31 additions & 1 deletion app/Domain/Timesheets/Templates/showMyMonthlyTimesheet.tpl.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,13 +200,43 @@

<form action="<?php echo BASE_URL ?>/timesheets/showMyMonthlyTimesheet" method="post" id="timesheetList">
<div class="btn-group viewDropDown pull-right">
<div style="position: relative; display: inline-block;">
<button style="cursor: pointer; background: none; border: none; font-size: 18px;margin-top:5px;">
&#x24D8;
<span style="
visibility: hidden;
opacity: 0;
position: absolute;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
background-color: #333;
color: white;
padding: 8px 12px;
border-radius: 6px;
white-space: nowrap;
font-size: 14px;
transition: opacity 0.3s, visibility 0.3s;
z-index: 1000;
">
You can export your timesheet in the <strong>List view</strong>.
</span>
</button>
</div>

<style>
button:hover span {
visibility: visible !important;
opacity: 1 !important;
}
</style>
<button class="btn dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-calendar-alt" style="margin-right:5px;"></i><?php echo "Monthly view" ?> <?= $tpl->__('links.view') ?>
</button>
<ul class="dropdown-menu">
<li><a href="<?php echo BASE_URL ?>/timesheets/showMy"><?php echo $tpl->__('links.week_view') ?></a></li>
<li><a href="<?php echo BASE_URL ?>/timesheets/showMyList"><?php echo $tpl->__('links.list_view') ?></a></li>
<li><a href="<?= BASE_URL ?>/timesheets/showMyMonthlyTimesheet" class="active"><i class="fa fa-calendar-alt" style="margin-right:5px;"></i>Monthly View</a></li>
<li><a href="<?php echo BASE_URL ?>/timesheets/showMyList"><?php echo $tpl->__('links.list_view') ?></a></li>
</ul>
</div>
<div class="pull-left" style="padding-left:5px; margin-top:-3px;">
Expand Down
Loading
Loading