style: auto-fix 1340 phpcs PSR-12 violations via phpcbf; exclude MissingNamespace and SideEffects
This commit is contained in:
+163
-130
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* TicketView.php — Individual ticket view, redesigned for TDS v1.2
|
||||
* Variables: $ticket, $comments (threaded), $timeline, $allUsers, $allowedTransitions
|
||||
@@ -20,8 +21,9 @@ $pageScripts = [
|
||||
];
|
||||
|
||||
// Helper functions
|
||||
function getEventIcon(string $actionType): string {
|
||||
return match($actionType) {
|
||||
function getEventIcon(string $actionType): string
|
||||
{
|
||||
return match ($actionType) {
|
||||
'create' => '[+]',
|
||||
'update' => '[~]',
|
||||
'comment' => '[>]',
|
||||
@@ -34,16 +36,23 @@ function getEventIcon(string $actionType): string {
|
||||
};
|
||||
}
|
||||
|
||||
function formatAction(array $event): string {
|
||||
function formatAction(array $event): string
|
||||
{
|
||||
$det = $event['details'] ?? [];
|
||||
switch ($event['action_type']) {
|
||||
case 'create':
|
||||
if (($event['entity_type'] ?? '') === 'comment') return 'posted a comment';
|
||||
if (($event['entity_type'] ?? '') === 'comment') {
|
||||
return 'posted a comment';
|
||||
}
|
||||
return 'created this ticket';
|
||||
case 'comment': return 'posted a comment';
|
||||
case 'view': return 'viewed this ticket';
|
||||
case 'attachment': return 'uploaded a file';
|
||||
case 'delete': return 'deleted a comment';
|
||||
case 'comment':
|
||||
return 'posted a comment';
|
||||
case 'view':
|
||||
return 'viewed this ticket';
|
||||
case 'attachment':
|
||||
return 'uploaded a file';
|
||||
case 'delete':
|
||||
return 'deleted a comment';
|
||||
case 'assign':
|
||||
if (is_array($det) && isset($det['assigned_to']['to'])) {
|
||||
$to = $det['assigned_to']['to'] ?: 'Unassigned';
|
||||
@@ -58,7 +67,9 @@ function formatAction(array $event): string {
|
||||
case 'update':
|
||||
if (is_array($det)) {
|
||||
$fields = array_keys(array_filter($det, fn($v) => is_array($v) && isset($v['from'], $v['to'])));
|
||||
if ($fields) return 'updated ' . implode(', ', array_map(fn($f) => str_replace('_', ' ', $f), $fields));
|
||||
if ($fields) {
|
||||
return 'updated ' . implode(', ', array_map(fn($f) => str_replace('_', ' ', $f), $fields));
|
||||
}
|
||||
}
|
||||
return 'updated this ticket';
|
||||
default:
|
||||
@@ -72,8 +83,11 @@ $ageDays = floor($ageSeconds / 86400);
|
||||
$ageHours = floor(($ageSeconds % 86400) / 3600);
|
||||
$ageClass = 'lt-text-muted';
|
||||
if ($ticket['status'] !== 'Closed') {
|
||||
if ($ageDays >= 10) $ageClass = 'lt-text-danger';
|
||||
elseif ($ageDays >= 5) $ageClass = 'lt-text-amber';
|
||||
if ($ageDays >= 10) {
|
||||
$ageClass = 'lt-text-danger';
|
||||
} elseif ($ageDays >= 5) {
|
||||
$ageClass = 'lt-text-amber';
|
||||
}
|
||||
}
|
||||
$ageStr = $ageDays > 0
|
||||
? $ageDays . ' day' . ($ageDays !== 1 ? 's' : '')
|
||||
@@ -93,12 +107,12 @@ $visUserModel = new UserModel($conn);
|
||||
$allAvailableGroups = $visUserModel->getAllGroups();
|
||||
|
||||
// JSON-encode ticket fields for the inline script
|
||||
$json_ticket_id = json_encode($ticket['ticket_id'], JSON_HEX_TAG);
|
||||
$json_title = json_encode($ticket['title'], JSON_HEX_TAG);
|
||||
$json_status = json_encode($ticket['status'], JSON_HEX_TAG);
|
||||
$json_priority = json_encode($ticket['priority'], JSON_HEX_TAG);
|
||||
$json_category = json_encode($ticket['category'], JSON_HEX_TAG);
|
||||
$json_type = json_encode($ticket['type'], JSON_HEX_TAG);
|
||||
$json_ticket_id = json_encode($ticket['ticket_id'], JSON_HEX_TAG);
|
||||
$json_title = json_encode($ticket['title'], JSON_HEX_TAG);
|
||||
$json_status = json_encode($ticket['status'], JSON_HEX_TAG);
|
||||
$json_priority = json_encode($ticket['priority'], JSON_HEX_TAG);
|
||||
$json_category = json_encode($ticket['category'], JSON_HEX_TAG);
|
||||
$json_type = json_encode($ticket['type'], JSON_HEX_TAG);
|
||||
$json_updated_at = json_encode($ticket['updated_at'], JSON_HEX_TAG);
|
||||
$json_total_comments = json_encode((int)$totalComments, JSON_HEX_TAG);
|
||||
$json_comment_page = json_encode((int)$commentPageSize, JSON_HEX_TAG);
|
||||
@@ -150,7 +164,7 @@ include __DIR__ . '/layout_header.php';
|
||||
<div class="lt-btn-group">
|
||||
<!-- Status dot indicator -->
|
||||
<?php
|
||||
$dotClass = match($ticket['status']) {
|
||||
$dotClass = match ($ticket['status']) {
|
||||
'Open' => 'lt-dot-up',
|
||||
'In Progress' => 'lt-dot-warn',
|
||||
'Pending' => 'lt-dot--orange',
|
||||
@@ -168,13 +182,17 @@ include __DIR__ . '/layout_header.php';
|
||||
<option value="<?= htmlspecialchars($ticket['status']) ?>" selected>
|
||||
<?= htmlspecialchars($ticket['status']) ?> (current)
|
||||
</option>
|
||||
<?php foreach ($allowedTransitions as $t): ?>
|
||||
<?php foreach ($allowedTransitions as $t) : ?>
|
||||
<option value="<?= htmlspecialchars($t['to_status']) ?>"
|
||||
data-requires-comment="<?= $t['requires_comment'] ? '1' : '0' ?>"
|
||||
data-requires-admin="<?= $t['requires_admin'] ? '1' : '0' ?>">
|
||||
<?= htmlspecialchars($t['to_status']) ?>
|
||||
<?php if ($t['requires_comment']): ?> *<?php endif ?>
|
||||
<?php if ($t['requires_admin']): ?> (Admin)<?php endif ?>
|
||||
<?= htmlspecialchars($t['to_status']) ?>
|
||||
<?php if ($t['requires_comment']) :
|
||||
?> *<?php
|
||||
endif ?>
|
||||
<?php if ($t['requires_admin']) :
|
||||
?> (Admin)<?php
|
||||
endif ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
@@ -191,18 +209,20 @@ include __DIR__ . '/layout_header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ($priorityNum <= 2 && $ticket['status'] !== 'Closed'): ?>
|
||||
<?php
|
||||
$slaTargetHours = match($priorityNum) { 1 => 8, 2 => 24, default => 72 };
|
||||
$elapsedSeconds = time() - strtotime($ticket['created_at']);
|
||||
$elapsedHours = round($elapsedSeconds / 3600, 1);
|
||||
$slaPct = min(100, round(($elapsedSeconds / ($slaTargetHours * 3600)) * 100));
|
||||
$slaBreached = $elapsedSeconds >= ($slaTargetHours * 3600);
|
||||
$alertClass = $priorityNum === 1 ? 'lt-alert--error' : 'lt-alert--warning';
|
||||
$alertIcon = $priorityNum === 1 ? '[ ! ]' : '[ ~ ]';
|
||||
$alertLabel = $priorityNum === 1 ? 'CRITICAL — P1 Ticket' : 'HIGH PRIORITY — P2 Ticket';
|
||||
$progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progress--red' : 'lt-progress--green');
|
||||
?>
|
||||
<?php if ($priorityNum <= 2 && $ticket['status'] !== 'Closed') : ?>
|
||||
<?php
|
||||
$slaTargetHours = match ($priorityNum) {
|
||||
1 => 8, 2 => 24, default => 72
|
||||
};
|
||||
$elapsedSeconds = time() - strtotime($ticket['created_at']);
|
||||
$elapsedHours = round($elapsedSeconds / 3600, 1);
|
||||
$slaPct = min(100, round(($elapsedSeconds / ($slaTargetHours * 3600)) * 100));
|
||||
$slaBreached = $elapsedSeconds >= ($slaTargetHours * 3600);
|
||||
$alertClass = $priorityNum === 1 ? 'lt-alert--error' : 'lt-alert--warning';
|
||||
$alertIcon = $priorityNum === 1 ? '[ ! ]' : '[ ~ ]';
|
||||
$alertLabel = $priorityNum === 1 ? 'CRITICAL — P1 Ticket' : 'HIGH PRIORITY — P2 Ticket';
|
||||
$progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progress--red' : 'lt-progress--green');
|
||||
?>
|
||||
<!-- Priority alert banner — P1/P2 only, dismissible per session -->
|
||||
<div class="lt-alert <?= $alertClass ?>" id="priorityAlertBanner"
|
||||
role="alert" aria-live="polite"
|
||||
@@ -216,9 +236,9 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-alert-msg">
|
||||
SLA target: <strong><?= $slaTargetHours ?>h</strong> —
|
||||
Elapsed: <strong id="slaElapsedTimer"><?= $elapsedHours ?>h</strong>
|
||||
<?php if (!$slaBreached): ?>
|
||||
<?php if (!$slaBreached) : ?>
|
||||
— Remaining: <strong id="slaCountdownTimer" class="lt-text-cyan"></strong>
|
||||
<?php else: ?>
|
||||
<?php else : ?>
|
||||
— <span class="lt-text-danger" id="slaCountdownTimer">SLA BREACHED (+<strong id="slaOverrunTimer"><?= round(($elapsedSeconds - $slaTargetHours * 3600) / 3600, 1) ?>h</strong>)</span>
|
||||
<?php endif ?>
|
||||
<div class="lt-progress lt-progress--sm <?= $progressClass ?>" id="slaProgress" style="margin-top:0.35rem"
|
||||
@@ -317,7 +337,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<span class="lt-kv-label">Priority</span>
|
||||
<span class="lt-kv-value">
|
||||
<select id="prioritySelect" class="lt-select lt-select-sm editable-metadata lt-display-field" aria-label="Priority">
|
||||
<?php foreach ([1=>'P1 - Critical',2=>'P2 - High',3=>'P3 - Medium',4=>'P4 - Low',5=>'P5 - Minimal'] as $v=>$l): ?>
|
||||
<?php foreach ([1 => 'P1 - Critical',2 => 'P2 - High',3 => 'P3 - Medium',4 => 'P4 - Low',5 => 'P5 - Minimal'] as $v => $l) : ?>
|
||||
<option value="<?= $v ?>" <?= (int)$ticket['priority'] === $v ? 'selected' : '' ?>><?= $l ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
@@ -326,13 +346,15 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-kv-row">
|
||||
<span class="lt-kv-label">Category</span>
|
||||
<span class="lt-kv-value">
|
||||
<?php $catColor = match($ticket['category']) { 'Hardware'=>'lt-tag--orange','Software'=>'lt-tag--cyan','Network'=>'lt-tag--purple','Security'=>'lt-tag--red',default=>'' }; ?>
|
||||
<?php $catColor = match ($ticket['category']) {
|
||||
'Hardware'=>'lt-tag--orange','Software'=>'lt-tag--cyan','Network'=>'lt-tag--purple','Security'=>'lt-tag--red',default=>''
|
||||
}; ?>
|
||||
<!-- Read mode tag — hidden in edit mode via CSS -->
|
||||
<span class="lt-tag <?= $catColor ?> read-mode-tag" id="categoryTag"
|
||||
aria-label="Category: <?= htmlspecialchars($ticket['category']) ?>"><?= htmlspecialchars($ticket['category']) ?></span>
|
||||
<!-- Edit mode select — shown only when editing -->
|
||||
<select id="categorySelect" class="lt-select lt-select-sm editable-metadata edit-mode-field" style="display:none" aria-label="Category">
|
||||
<?php foreach (['Hardware','Software','Network','Security','General'] as $c): ?>
|
||||
<?php foreach (['Hardware','Software','Network','Security','General'] as $c) : ?>
|
||||
<option value="<?= $c ?>" <?= $ticket['category'] === $c ? 'selected' : '' ?>><?= $c ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
@@ -341,13 +363,15 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-kv-row">
|
||||
<span class="lt-kv-label">Type</span>
|
||||
<span class="lt-kv-value">
|
||||
<?php $typeColor = match($ticket['type']) { 'Maintenance'=>'lt-tag--orange','Issue'=>'lt-tag--red','Problem'=>'lt-tag--red','Upgrade'=>'lt-tag--purple','Install'=>'lt-tag--cyan',default=>'' }; ?>
|
||||
<?php $typeColor = match ($ticket['type']) {
|
||||
'Maintenance'=>'lt-tag--orange','Issue'=>'lt-tag--red','Problem'=>'lt-tag--red','Upgrade'=>'lt-tag--purple','Install'=>'lt-tag--cyan',default=>''
|
||||
}; ?>
|
||||
<!-- Read mode tag — hidden in edit mode via CSS -->
|
||||
<span class="lt-tag <?= $typeColor ?> read-mode-tag" id="typeTag"
|
||||
aria-label="Type: <?= htmlspecialchars($ticket['type']) ?>"><?= htmlspecialchars($ticket['type']) ?></span>
|
||||
<!-- Edit mode select — shown only when editing -->
|
||||
<select id="typeSelect" class="lt-select lt-select-sm editable-metadata edit-mode-field" style="display:none" aria-label="Type">
|
||||
<?php foreach (['Maintenance','Install','Task','Upgrade','Issue','Problem'] as $t): ?>
|
||||
<?php foreach (['Maintenance','Install','Task','Upgrade','Issue','Problem'] as $t) : ?>
|
||||
<option value="<?= $t ?>" <?= $ticket['type'] === $t ? 'selected' : '' ?>><?= $t ?></option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
@@ -358,7 +382,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<span class="lt-kv-value">
|
||||
<select id="assignedToSelect" class="lt-select lt-select-sm" aria-label="Assign ticket">
|
||||
<option value="">Unassigned</option>
|
||||
<?php foreach ($allUsers as $u): ?>
|
||||
<?php foreach ($allUsers as $u) : ?>
|
||||
<option value="<?= (int)$u['user_id'] ?>"
|
||||
<?= ((int)$ticket['assigned_to'] === (int)$u['user_id']) ? 'selected' : '' ?>>
|
||||
<?= htmlspecialchars($u['display_name'] ?? $u['username']) ?>
|
||||
@@ -387,7 +411,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-kv-row">
|
||||
<span class="lt-kv-label">Created By</span>
|
||||
<span class="lt-kv-value"><?= htmlspecialchars($creator) ?>
|
||||
<?php if (!empty($ticket['created_at'])): ?>
|
||||
<?php if (!empty($ticket['created_at'])) : ?>
|
||||
<span class="lt-text-muted lt-text-xs"> —
|
||||
<span class="ts-cell" data-ts="<?= htmlspecialchars($ticket['created_at'], ENT_QUOTES, 'UTF-8') ?>"
|
||||
title="<?= date('Y-m-d H:i T', strtotime($ticket['created_at'])) ?>">
|
||||
@@ -397,19 +421,19 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<?php endif ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php if (!empty($ticket['updater_display_name']) || !empty($ticket['updater_username'])): ?>
|
||||
<?php if (!empty($ticket['updater_display_name']) || !empty($ticket['updater_username'])) : ?>
|
||||
<div class="lt-kv-row">
|
||||
<span class="lt-kv-label">Last Updated</span>
|
||||
<span class="lt-kv-value">
|
||||
<?= htmlspecialchars($ticket['updater_display_name'] ?? $ticket['updater_username']) ?>
|
||||
<?php if (!empty($ticket['updated_at'])): ?>
|
||||
<?= htmlspecialchars($ticket['updater_display_name'] ?? $ticket['updater_username']) ?>
|
||||
<?php if (!empty($ticket['updated_at'])) : ?>
|
||||
<span class="lt-text-muted lt-text-xs"> —
|
||||
<span class="ts-cell" data-ts="<?= htmlspecialchars($ticket['updated_at'], ENT_QUOTES, 'UTF-8') ?>"
|
||||
title="<?= date('Y-m-d H:i T', strtotime($ticket['updated_at'])) ?>">
|
||||
<?= date('M d, Y H:i', strtotime($ticket['updated_at'])) ?>
|
||||
</span>
|
||||
</span>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
@@ -421,8 +445,8 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-form-group">
|
||||
<label class="lt-label lt-text-cyan">Allowed Groups</label>
|
||||
<div class="visibility-groups-edit lt-flex lt-flex-wrap lt-flex-gap-sm">
|
||||
<?php foreach ($allAvailableGroups as $group):
|
||||
$isChecked = in_array($group, $currentVisibilityGroups, true); ?>
|
||||
<?php foreach ($allAvailableGroups as $group) :
|
||||
$isChecked = in_array($group, $currentVisibilityGroups, true); ?>
|
||||
<label class="lt-filter-option">
|
||||
<input type="checkbox" class="lt-checkbox visibility-group-checkbox editable-metadata lt-display-field"
|
||||
value="<?= htmlspecialchars($group, ENT_QUOTES, 'UTF-8') ?>"
|
||||
@@ -430,7 +454,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<span class="lt-badge"><?= htmlspecialchars($group) ?></span>
|
||||
</label>
|
||||
<?php endforeach ?>
|
||||
<?php if (empty($allAvailableGroups)): ?>
|
||||
<?php if (empty($allAvailableGroups)) : ?>
|
||||
<span class="lt-text-muted">No groups available</span>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
@@ -451,7 +475,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<button type="button" class="lt-tab" id="comments-tab-btn"
|
||||
role="tab" data-tab="comments-panel" aria-selected="false" aria-controls="comments-panel">
|
||||
Comments
|
||||
<?php if (!empty($comments)): ?>
|
||||
<?php if (!empty($comments)) : ?>
|
||||
<span class="lt-badge lt-badge-sm"><?= count($comments) ?></span>
|
||||
<?php endif ?>
|
||||
</button>
|
||||
@@ -541,39 +565,42 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<div class="lt-section-header">Comment History</div>
|
||||
<div class="lt-section-body">
|
||||
<div class="comments-list" id="commentsList">
|
||||
<?php if (empty($comments)): ?>
|
||||
<?php if (empty($comments)) : ?>
|
||||
<div class="lt-empty">No comments yet. Be the first to comment.</div>
|
||||
<?php else: ?>
|
||||
<?php
|
||||
function renderComment(array $comment, ?int $currentUserId, bool $isAdmin, int $depth = 0): void {
|
||||
$displayName = $comment['display_name_formatted'] ?? $comment['user_name'] ?? 'Unknown User';
|
||||
$commentId = (int)$comment['comment_id'];
|
||||
$isOwner = ((int)$comment['user_id'] === (int)$currentUserId);
|
||||
$canModify = $isOwner || $isAdmin;
|
||||
$markdownEnabled = (bool)($comment['markdown_enabled'] ?? false);
|
||||
$threadDepth = (int)($comment['thread_depth'] ?? $depth);
|
||||
$parentId = $comment['parent_comment_id'] ?? null;
|
||||
$depthClass = 'thread-depth-' . min($threadDepth, 3);
|
||||
$threadClass = $parentId ? 'comment-reply' : 'comment-root';
|
||||
$dateStr = date('M d, Y H:i', strtotime($comment['created_at']));
|
||||
$editedIndicator = !empty($comment['updated_at']) ? ' <span class="comment-edited lt-text-xs lt-text-muted">(edited)</span>' : '';
|
||||
// Avatar initials + color (fallback when no photo)
|
||||
$words = array_filter(explode(' ', $displayName));
|
||||
$initials = strtoupper(implode('', array_map(fn($w) => $w[0], array_slice($words, 0, 2))));
|
||||
$avatarColors = ['lt-avatar--orange', 'lt-avatar--green', 'lt-avatar--purple', ''];
|
||||
$avatarColor = $avatarColors[abs(crc32($displayName)) % count($avatarColors)];
|
||||
$commentUserId = (int)($comment['user_id'] ?? 0);
|
||||
?>
|
||||
<?php else : ?>
|
||||
<?php
|
||||
function renderComment(array $comment, ?int $currentUserId, bool $isAdmin, int $depth = 0): void
|
||||
{
|
||||
$displayName = $comment['display_name_formatted'] ?? $comment['user_name'] ?? 'Unknown User';
|
||||
$commentId = (int)$comment['comment_id'];
|
||||
$isOwner = ((int)$comment['user_id'] === (int)$currentUserId);
|
||||
$canModify = $isOwner || $isAdmin;
|
||||
$markdownEnabled = (bool)($comment['markdown_enabled'] ?? false);
|
||||
$threadDepth = (int)($comment['thread_depth'] ?? $depth);
|
||||
$parentId = $comment['parent_comment_id'] ?? null;
|
||||
$depthClass = 'thread-depth-' . min($threadDepth, 3);
|
||||
$threadClass = $parentId ? 'comment-reply' : 'comment-root';
|
||||
$dateStr = date('M d, Y H:i', strtotime($comment['created_at']));
|
||||
$editedIndicator = !empty($comment['updated_at']) ? ' <span class="comment-edited lt-text-xs lt-text-muted">(edited)</span>' : '';
|
||||
// Avatar initials + color (fallback when no photo)
|
||||
$words = array_filter(explode(' ', $displayName));
|
||||
$initials = strtoupper(implode('', array_map(fn($w) => $w[0], array_slice($words, 0, 2))));
|
||||
$avatarColors = ['lt-avatar--orange', 'lt-avatar--green', 'lt-avatar--purple', ''];
|
||||
$avatarColor = $avatarColors[abs(crc32($displayName)) % count($avatarColors)];
|
||||
$commentUserId = (int)($comment['user_id'] ?? 0);
|
||||
?>
|
||||
<div class="comment <?= $depthClass ?> <?= $threadClass ?>"
|
||||
data-comment-id="<?= $commentId ?>"
|
||||
data-markdown-enabled="<?= $markdownEnabled ? '1' : '0' ?>"
|
||||
data-thread-depth="<?= $threadDepth ?>"
|
||||
data-parent-id="<?= htmlspecialchars((string)($parentId ?? ''), ENT_QUOTES, 'UTF-8') ?>">
|
||||
<?php if ($parentId): ?><div class="thread-line" aria-hidden="true"></div><?php endif ?>
|
||||
<?php if ($parentId) :
|
||||
?><div class="thread-line" aria-hidden="true"></div><?php
|
||||
endif ?>
|
||||
<div class="comment-content">
|
||||
<div class="comment-header lt-flex lt-flex-gap-sm lt-flex-align-center">
|
||||
<div class="lt-avatar lt-avatar--xs <?= $avatarColor ?>" aria-hidden="true">
|
||||
<?php if ($commentUserId > 0): ?>
|
||||
<?php if ($commentUserId > 0) : ?>
|
||||
<img src="/api/user_avatar.php?user_id=<?= $commentUserId ?>"
|
||||
alt=""
|
||||
class="lt-avatar-img">
|
||||
@@ -588,14 +615,14 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<?= $editedIndicator ?>
|
||||
</span>
|
||||
<div class="comment-actions lt-btn-group">
|
||||
<?php if ($threadDepth < 3): ?>
|
||||
<?php if ($threadDepth < 3) : ?>
|
||||
<button type="button" class="lt-btn lt-btn-ghost lt-btn-sm comment-action-btn reply-btn"
|
||||
data-action="reply-comment"
|
||||
data-comment-id="<?= $commentId ?>"
|
||||
data-user="<?= htmlspecialchars($displayName, ENT_QUOTES) ?>"
|
||||
aria-label="Reply to comment">Reply</button>
|
||||
<?php endif ?>
|
||||
<?php if ($canModify): ?>
|
||||
<?php if ($canModify) : ?>
|
||||
<button type="button" class="lt-btn lt-btn-ghost lt-btn-sm comment-action-btn edit-btn"
|
||||
data-action="edit-comment"
|
||||
data-comment-id="<?= $commentId ?>"
|
||||
@@ -617,19 +644,21 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
id="comment-raw-<?= $commentId ?>"
|
||||
aria-hidden="true"><?= htmlspecialchars($comment['comment_text']) ?></textarea>
|
||||
</div>
|
||||
<?php if (!empty($comment['replies'])): ?>
|
||||
<?php if (!empty($comment['replies'])) : ?>
|
||||
<div class="comment-replies">
|
||||
<?php foreach ($comment['replies'] as $reply): ?>
|
||||
<?php renderComment($reply, $currentUserId, $isAdmin, $threadDepth + 1); ?>
|
||||
<?php endforeach ?>
|
||||
<?php foreach ($comment['replies'] as $reply) : ?>
|
||||
<?php renderComment($reply, $currentUserId, $isAdmin, $threadDepth + 1); ?>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
foreach ($comments as $comment): renderComment($comment, $currentUserId, $isAdmin); endforeach;
|
||||
?>
|
||||
<?php if ($totalComments > $commentPageSize): ?>
|
||||
<?php
|
||||
}
|
||||
foreach ($comments as $comment) :
|
||||
renderComment($comment, $currentUserId, $isAdmin);
|
||||
endforeach;
|
||||
?>
|
||||
<?php if ($totalComments > $commentPageSize) : ?>
|
||||
<div id="loadMoreComments" class="lt-flex lt-flex-center lt-mt-md">
|
||||
<button type="button" id="loadMoreBtn" class="lt-btn lt-btn-ghost lt-btn-sm">
|
||||
Load more comments
|
||||
@@ -638,7 +667,7 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -748,27 +777,27 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<span class="lt-frame-bl">╚</span><span class="lt-frame-br">╝</span>
|
||||
<div class="lt-section-header">Activity Timeline</div>
|
||||
<div class="lt-section-body">
|
||||
<?php if (empty($timeline)): ?>
|
||||
<?php if (empty($timeline)) : ?>
|
||||
<div class="lt-empty">No activity recorded yet.</div>
|
||||
<?php else: ?>
|
||||
<?php else : ?>
|
||||
<div class="lt-timeline">
|
||||
<?php foreach ($timeline as $event): ?>
|
||||
<?php
|
||||
$actor = htmlspecialchars($event['display_name'] ?? $event['username'] ?? 'System');
|
||||
$action = formatAction($event);
|
||||
$icon = getEventIcon($event['action_type']);
|
||||
$evtFmt = date('M d, Y H:i', strtotime($event['created_at']));
|
||||
$tClass = match($event['action_type']) {
|
||||
'create' => 'lt-timeline-item--green',
|
||||
'status_change' => 'lt-timeline-item--cyan',
|
||||
'comment' => 'lt-timeline-item--green',
|
||||
'assign' => 'lt-timeline-item--orange',
|
||||
'attachment' => 'lt-timeline-item--orange',
|
||||
'update' => '',
|
||||
'delete' => 'lt-timeline-item--red',
|
||||
default => 'lt-timeline-item--dim',
|
||||
};
|
||||
?>
|
||||
<?php foreach ($timeline as $event) : ?>
|
||||
<?php
|
||||
$actor = htmlspecialchars($event['display_name'] ?? $event['username'] ?? 'System');
|
||||
$action = formatAction($event);
|
||||
$icon = getEventIcon($event['action_type']);
|
||||
$evtFmt = date('M d, Y H:i', strtotime($event['created_at']));
|
||||
$tClass = match ($event['action_type']) {
|
||||
'create' => 'lt-timeline-item--green',
|
||||
'status_change' => 'lt-timeline-item--cyan',
|
||||
'comment' => 'lt-timeline-item--green',
|
||||
'assign' => 'lt-timeline-item--orange',
|
||||
'attachment' => 'lt-timeline-item--orange',
|
||||
'update' => '',
|
||||
'delete' => 'lt-timeline-item--red',
|
||||
default => 'lt-timeline-item--dim',
|
||||
};
|
||||
?>
|
||||
<div class="lt-timeline-item <?= $tClass ?>">
|
||||
<div class="lt-timeline-meta">
|
||||
<span class="lt-timeline-icon lt-text-xs" aria-hidden="true"><?= $icon ?></span>
|
||||
@@ -778,34 +807,36 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
data-ts="<?= htmlspecialchars($event['created_at'], ENT_QUOTES, 'UTF-8') ?>"
|
||||
title="<?= $evtFmt ?>"><?= $evtFmt ?></span>
|
||||
</div>
|
||||
<?php if (!empty($event['details']) && !in_array($event['action_type'], ['status_change', 'assign', 'comment', 'view'], true)): ?>
|
||||
<?php if (!empty($event['details']) && !in_array($event['action_type'], ['status_change', 'assign', 'comment', 'view'], true)) : ?>
|
||||
<div class="lt-timeline-body lt-text-xs lt-text-muted">
|
||||
<?php
|
||||
$det = $event['details'];
|
||||
if (is_array($det)) {
|
||||
$parts = [];
|
||||
foreach ($det as $k => $v) {
|
||||
if (is_array($v) && isset($v['from'], $v['to'])) {
|
||||
$label = ucfirst(str_replace('_', ' ', $k));
|
||||
$from = mb_strlen((string)$v['from']) > 60
|
||||
<?php
|
||||
$det = $event['details'];
|
||||
if (is_array($det)) {
|
||||
$parts = [];
|
||||
foreach ($det as $k => $v) {
|
||||
if (is_array($v) && isset($v['from'], $v['to'])) {
|
||||
$label = ucfirst(str_replace('_', ' ', $k));
|
||||
$from = mb_strlen((string)$v['from']) > 60
|
||||
? mb_substr((string)$v['from'], 0, 60) . '…'
|
||||
: (string)$v['from'];
|
||||
$to = mb_strlen((string)$v['to']) > 60
|
||||
$to = mb_strlen((string)$v['to']) > 60
|
||||
? mb_substr((string)$v['to'], 0, 60) . '…'
|
||||
: (string)$v['to'];
|
||||
$parts[] = '<strong>' . htmlspecialchars($label) . ':</strong> '
|
||||
$parts[] = '<strong>' . htmlspecialchars($label) . ':</strong> '
|
||||
. '<span class="lt-text-muted">' . htmlspecialchars($from) . '</span>'
|
||||
. ' <span class="lt-text-amber">→</span> '
|
||||
. '<span class="lt-text-cyan">' . htmlspecialchars($to) . '</span>';
|
||||
} elseif (!in_array($k, ['old_value', 'new_value'], true)) {
|
||||
$parts[] = '<strong>' . htmlspecialchars($k) . ':</strong> ' . htmlspecialchars((string)$v);
|
||||
}
|
||||
}
|
||||
if ($parts) echo implode('<br>', $parts);
|
||||
}
|
||||
?>
|
||||
} elseif (!in_array($k, ['old_value', 'new_value'], true)) {
|
||||
$parts[] = '<strong>' . htmlspecialchars($k) . ':</strong> ' . htmlspecialchars((string)$v);
|
||||
}
|
||||
}
|
||||
if ($parts) {
|
||||
echo implode('<br>', $parts);
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
@@ -896,12 +927,14 @@ $progressClass = $slaBreached ? 'lt-progress--red' : ($slaPct >= 75 ? 'lt-progr
|
||||
<span class="lt-kv-label">Groups</span>
|
||||
<span class="lt-kv-value">
|
||||
<?php
|
||||
$groups = array_filter(array_map('trim', explode(',', $GLOBALS['currentUser']['groups'] ?? '')));
|
||||
if ($groups): foreach ($groups as $g): ?>
|
||||
$groups = array_filter(array_map('trim', explode(',', $GLOBALS['currentUser']['groups'] ?? '')));
|
||||
if ($groups) :
|
||||
foreach ($groups as $g) : ?>
|
||||
<span class="lt-badge lt-badge-sm"><?= htmlspecialchars($g) ?></span>
|
||||
<?php endforeach; else: ?>
|
||||
<?php endforeach;
|
||||
else : ?>
|
||||
<span class="lt-text-muted">None</span>
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user