Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67a7d769f0 | |||
| 84b104a501 | |||
| ff109a710c |
@@ -120,7 +120,7 @@ try {
|
||||
$stmt = $conn->prepare("UPDATE status_transitions SET
|
||||
from_status = ?, to_status = ?, requires_comment = ?, requires_admin = ?, is_active = ?
|
||||
WHERE transition_id = ?");
|
||||
$stmt->bind_param('ssiiiii',
|
||||
$stmt->bind_param('ssiiii',
|
||||
$data['from_status'],
|
||||
$data['to_status'],
|
||||
$data['requires_comment'] ?? 0,
|
||||
|
||||
@@ -686,7 +686,9 @@ function closeBulkPriorityModal() {
|
||||
}
|
||||
|
||||
function performBulkPriority() {
|
||||
const priority = document.getElementById('bulkPriority').value;
|
||||
const priorityEl = document.getElementById('bulkPriority');
|
||||
if (!priorityEl) return;
|
||||
const priority = priorityEl.value;
|
||||
const ticketIds = getSelectedTicketIds();
|
||||
|
||||
if (!priority) {
|
||||
@@ -789,7 +791,9 @@ function closeBulkStatusModal() {
|
||||
}
|
||||
|
||||
function performBulkStatusChange() {
|
||||
const status = document.getElementById('bulkStatus').value;
|
||||
const bulkStatusEl = document.getElementById('bulkStatus');
|
||||
if (!bulkStatusEl) return;
|
||||
const status = bulkStatusEl.value;
|
||||
const ticketIds = getSelectedTicketIds();
|
||||
|
||||
if (!status) {
|
||||
@@ -986,7 +990,9 @@ function closeQuickStatusModal() {
|
||||
}
|
||||
|
||||
function performQuickStatusChange(ticketId) {
|
||||
const newStatus = document.getElementById('quickStatusSelect').value;
|
||||
const quickStatusEl = document.getElementById('quickStatusSelect');
|
||||
if (!quickStatusEl) return;
|
||||
const newStatus = quickStatusEl.value;
|
||||
|
||||
lt.api.post('/api/update_ticket.php', { ticket_id: ticketId, status: newStatus })
|
||||
.then(data => {
|
||||
|
||||
+1
-1
@@ -1528,7 +1528,7 @@ function submitReply(parentCommentId) {
|
||||
<div class="comment-text" id="comment-text-${data.comment_id}" ${isMarkdownEnabled ? 'data-markdown' : ''}>
|
||||
${displayText}
|
||||
</div>
|
||||
<textarea class="comment-edit-raw" id="comment-raw-${data.comment_id}" style="display:none;">${commentText.replace(/</g, '<').replace(/>/g, '>')}</textarea>
|
||||
<textarea class="comment-edit-raw is-hidden" id="comment-raw-${data.comment_id}">${commentText.replace(/</g, '<').replace(/>/g, '>')}</textarea>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
||||
@@ -136,10 +136,16 @@ class DashboardController {
|
||||
|
||||
// Validate user ID filters
|
||||
$createdBy = $this->validateUserId($_GET['created_by'] ?? null);
|
||||
$assignedTo = $this->validateUserId($_GET['assigned_to'] ?? null);
|
||||
|
||||
if ($createdBy !== null) $filters['created_by'] = $createdBy;
|
||||
|
||||
// assigned_to accepts a numeric user ID or the special string 'unassigned'
|
||||
$assignedToRaw = $_GET['assigned_to'] ?? null;
|
||||
if ($assignedToRaw === 'unassigned') {
|
||||
$filters['assigned_to'] = 'unassigned';
|
||||
} else {
|
||||
$assignedTo = $this->validateUserId($assignedToRaw);
|
||||
if ($assignedTo !== null) $filters['assigned_to'] = $assignedTo;
|
||||
}
|
||||
|
||||
// Get tickets with pagination, sorting, search, and advanced filters
|
||||
$result = $this->ticketModel->getAllTickets($page, $limit, $status, $sortColumn, $sortDirection, $category, $type, $search, $filters, $GLOBALS['currentUser'] ?? []);
|
||||
|
||||
@@ -185,7 +185,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<p id="visibilityHint" class="lt-form-hint">Everyone who is logged in can view this ticket.</p>
|
||||
</div>
|
||||
|
||||
<div id="visibilityGroupsContainer" class="lt-form-group is-hidden" aria-live="polite">
|
||||
<div id="visibilityGroupsContainer" class="lt-form-group is-hidden" aria-live="polite" aria-describedby="visibilityGroupsHint">
|
||||
<label class="lt-label lt-text-cyan">Allowed Groups</label>
|
||||
<div class="visibility-groups-list lt-flex lt-flex-wrap lt-flex-gap-sm">
|
||||
<?php
|
||||
@@ -205,7 +205,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<span class="lt-text-muted lt-text-sm">No groups available</span>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<p class="lt-form-hint lt-form-hint--warn">Select at least one group for Internal visibility.</p>
|
||||
<p id="visibilityGroupsHint" class="lt-form-hint lt-form-hint--warn">Select at least one group for Internal visibility.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -331,7 +331,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<div class="workload-item">
|
||||
<div class="lt-avatar lt-avatar--sm <?= $avatarColor ?>" aria-hidden="true" title="<?= htmlspecialchars($name) ?>">
|
||||
<?php if ($userId > 0): ?>
|
||||
<img src="/api/user_avatar.php?user_id=<?= $userId ?>" alt="" class="lt-avatar-img" onerror="this.style.display='none'">
|
||||
<img src="/api/user_avatar.php?user_id=<?= $userId ?>" alt="" class="lt-avatar-img">
|
||||
<?php endif ?>
|
||||
<span class="lt-avatar-initials"><?= htmlspecialchars($initials) ?></span>
|
||||
</div>
|
||||
@@ -1269,7 +1269,7 @@ if (advForm) advForm.addEventListener('submit', performAdvancedSearch);
|
||||
(age ? '<div class="lt-kv-row"><span class="lt-kv-label">Age</span><span class="lt-kv-value">' + esc(age) + '</span></div>' : '') +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<p class="lt-text-muted lt-text-xs" style="text-align:center">Click "Open Full Ticket" for description, comments & attachments.</p>';
|
||||
'<p class="lt-text-muted lt-text-xs lt-text-center">Click "Open Full Ticket" for description, comments & attachments.</p>';
|
||||
|
||||
lt.rightDrawer.open('ticketPreviewDrawer');
|
||||
}
|
||||
|
||||
+12
-13
@@ -212,12 +212,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="lt-alert-close" aria-label="Dismiss"
|
||||
onclick="(function(btn){
|
||||
var id=btn.closest('[data-alert-id]').dataset.alertId;
|
||||
try{sessionStorage.setItem('lt_dismissed_'+id,'1');}catch(e){}
|
||||
btn.closest('.lt-alert').classList.add('dismissed');
|
||||
})(this)">✕</button>
|
||||
<button type="button" class="lt-alert-close" data-action="dismiss-priority-banner" aria-label="Dismiss">✕</button>
|
||||
</div>
|
||||
<script nonce="<?= htmlspecialchars($nonce, ENT_QUOTES, 'UTF-8') ?>">
|
||||
(function(){
|
||||
@@ -564,8 +559,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<?php if ($commentUserId > 0): ?>
|
||||
<img src="/api/user_avatar.php?user_id=<?= $commentUserId ?>"
|
||||
alt=""
|
||||
class="lt-avatar-img"
|
||||
onerror="this.style.display='none'">
|
||||
class="lt-avatar-img">
|
||||
<?php endif ?>
|
||||
<span class="lt-avatar-initials"><?= htmlspecialchars($initials) ?></span>
|
||||
</div>
|
||||
@@ -602,9 +596,8 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
? htmlspecialchars($comment['comment_text'])
|
||||
: nl2br(htmlspecialchars($comment['comment_text'])) ?>
|
||||
</div>
|
||||
<textarea class="lt-input lt-textarea comment-edit-raw"
|
||||
<textarea class="lt-input lt-textarea comment-edit-raw is-hidden"
|
||||
id="comment-raw-<?= $commentId ?>"
|
||||
style="display:none"
|
||||
aria-hidden="true"><?= htmlspecialchars($comment['comment_text']) ?></textarea>
|
||||
</div>
|
||||
<?php if (!empty($comment['replies'])): ?>
|
||||
@@ -978,7 +971,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
for (var i = 0; i < (w.display_name || '').length; i++) hash = ((hash << 5) - hash + (w.display_name || '').charCodeAt(i)) | 0;
|
||||
var color = avatarColors[Math.abs(hash) % 4];
|
||||
html += '<div class="lt-avatar lt-avatar--xs ' + color + '" title="' + lt.escHtml(w.display_name) + '" aria-label="' + lt.escHtml(w.display_name) + '">' +
|
||||
'<img src="/api/user_avatar.php?user_id=' + w.user_id + '" alt="" class="lt-avatar-img" onerror="this.style.display=\'none\'">' +
|
||||
'<img src="/api/user_avatar.php?user_id=' + w.user_id + '" alt="" class="lt-avatar-img">' +
|
||||
'<span class="lt-avatar-initials">' + lt.escHtml(initials) + '</span>' +
|
||||
'</div>';
|
||||
});
|
||||
@@ -1121,6 +1114,12 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
if (typeof editComment === 'function') editComment(parseInt(commentId, 10));
|
||||
} else if (action === 'delete-comment' && commentId) {
|
||||
if (typeof deleteComment === 'function') deleteComment(parseInt(commentId, 10));
|
||||
} else if (action === 'dismiss-priority-banner') {
|
||||
var banner = target.closest('[data-alert-id]');
|
||||
if (banner) {
|
||||
try { sessionStorage.setItem('lt_dismissed_' + banner.dataset.alertId, '1'); } catch(ex) {}
|
||||
banner.classList.add('dismissed');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1237,7 +1236,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
' data-action="delete-comment" data-comment-id="' + commentId + '" aria-label="Delete comment">Del</button>' : '';
|
||||
var threadLine = parentId ? '<div class="thread-line" aria-hidden="true"></div>' : '';
|
||||
var avatarImg = userId > 0 ?
|
||||
'<img src="/api/user_avatar.php?user_id=' + userId + '" alt="" class="lt-avatar-img" onerror="this.style.display=\'none\'">' : '';
|
||||
'<img src="/api/user_avatar.php?user_id=' + userId + '" alt="" class="lt-avatar-img">' : '';
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.className = 'comment ' + depthClass + ' ' + threadClass;
|
||||
@@ -1263,7 +1262,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
'<div class="comment-text" id="comment-text-' + commentId + '"' + (mdEnabled ? ' data-markdown data-rendered="1"' : '') + '>' +
|
||||
commentText +
|
||||
'</div>' +
|
||||
'<textarea class="lt-input lt-textarea comment-edit-raw" id="comment-raw-' + commentId + '" style="display:none" aria-hidden="true">' +
|
||||
'<textarea class="lt-input lt-textarea comment-edit-raw is-hidden" id="comment-raw-' + commentId + '" aria-hidden="true">' +
|
||||
escapedRaw +
|
||||
'</textarea>' +
|
||||
'</div>';
|
||||
|
||||
@@ -50,7 +50,7 @@ include __DIR__ . '/../../views/layout_header.php';
|
||||
<td data-label="Label"><strong><?= htmlspecialchars($field['field_label']) ?></strong></td>
|
||||
<td data-label="Type" class="lt-text-xs"><?= ucfirst($field['field_type']) ?></td>
|
||||
<td data-label="Category" class="lt-text-xs"><?= htmlspecialchars($field['category'] ?? 'All') ?></td>
|
||||
<td data-label="Required" style="text-align:center">
|
||||
<td data-label="Required" class="lt-text-center">
|
||||
<?= $field['is_required'] ? '<span class="lt-text-amber">✓</span>' : '<span class="lt-text-muted">—</span>' ?>
|
||||
</td>
|
||||
<td data-label="Status">
|
||||
|
||||
@@ -31,13 +31,13 @@ include __DIR__ . '/../../views/layout_header.php';
|
||||
$toCount = 0;
|
||||
if (isset($workflows)) { foreach ($workflows as $w) { if ($w['from_status'] === $status) $toCount++; } }
|
||||
?>
|
||||
<div class="lt-card" style="text-align:center">
|
||||
<div class="lt-card lt-text-center">
|
||||
<span class="lt-status lt-status-<?= $slug ?>"><?= $status ?></span>
|
||||
<div class="lt-text-xs lt-text-muted lt-mt-sm">→ <?= $toCount ?> transition<?= $toCount !== 1 ? 's' : '' ?></div>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<p class="lt-text-xs lt-text-muted" style="margin-top:0.5rem">
|
||||
<p class="lt-text-xs lt-text-muted lt-mt-sm">
|
||||
Define which status transitions are allowed. This controls what options appear in the status dropdown on tickets.
|
||||
</p>
|
||||
</div>
|
||||
@@ -69,17 +69,17 @@ include __DIR__ . '/../../views/layout_header.php';
|
||||
<td data-label="From">
|
||||
<span class="lt-status lt-status-<?= $fromSlug ?>"><?= htmlspecialchars($wf['from_status']) ?></span>
|
||||
</td>
|
||||
<td class="lt-text-amber lt-text-xs" style="text-align:center">→</td>
|
||||
<td class="lt-text-amber lt-text-xs lt-text-center">→</td>
|
||||
<td data-label="To">
|
||||
<span class="lt-status lt-status-<?= $toSlug ?>"><?= htmlspecialchars($wf['to_status']) ?></span>
|
||||
</td>
|
||||
<td data-label="Req. Comment" style="text-align:center">
|
||||
<td data-label="Req. Comment" class="lt-text-center">
|
||||
<?= $wf['requires_comment'] ? '<span class="lt-text-cyan">✓</span>' : '<span class="lt-text-muted">—</span>' ?>
|
||||
</td>
|
||||
<td data-label="Req. Admin" style="text-align:center">
|
||||
<td data-label="Req. Admin" class="lt-text-center">
|
||||
<?= $wf['requires_admin'] ? '<span class="lt-text-amber">✓</span>' : '<span class="lt-text-muted">—</span>' ?>
|
||||
</td>
|
||||
<td data-label="Active" style="text-align:center">
|
||||
<td data-label="Active" class="lt-text-center">
|
||||
<?= $wf['is_active']
|
||||
? '<span class="lt-text-cyan">✓</span>'
|
||||
: '<span class="lt-text-danger">✗</span>' ?>
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ include __DIR__ . '/../views/layout_header.php';
|
||||
<div class="lt-frame" style="max-width:32rem;margin:4rem auto">
|
||||
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header lt-text-danger">[ 403 ] ACCESS DENIED</div>
|
||||
<div class="lt-section-body" style="text-align:center">
|
||||
<div class="lt-section-body lt-text-center">
|
||||
<p class="lt-text-muted lt-mb-md">You do not have permission to access this resource.</p>
|
||||
<a href="/" class="lt-btn lt-btn-primary">← Dashboard</a>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ include __DIR__ . '/../views/layout_header.php';
|
||||
<div class="lt-frame" style="max-width:32rem;margin:4rem auto">
|
||||
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header lt-text-amber">[ 404 ] NOT FOUND</div>
|
||||
<div class="lt-section-body" style="text-align:center">
|
||||
<div class="lt-section-body lt-text-center">
|
||||
<p class="lt-text-muted lt-mb-md">The page you requested does not exist.</p>
|
||||
<a href="/" class="lt-btn lt-btn-primary">← Dashboard</a>
|
||||
</div>
|
||||
|
||||
@@ -166,7 +166,6 @@ $_lt_assetVer = $GLOBALS['config']['ASSET_VERSION'] ?? '20260329';
|
||||
<img src="/api/user_avatar.php?user_id=<?= $_lt_userId ?>"
|
||||
alt=""
|
||||
class="lt-avatar-img"
|
||||
onerror="this.style.display='none'">
|
||||
<?php endif ?>
|
||||
<span class="lt-avatar-initials"><?= htmlspecialchars($_lt_initials) ?></span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user