Fix notification comment query, status title, and is-hidden visibility
notifications.php: comment notifications never fired because the query
used action_type='comment'/entity_type='ticket' but logCommentCreate
logs action_type='create'/entity_type='comment'. Fix query to match
actual log format and extract ticket_id from details JSON.
notifications.php: status change notification titles always showed
"? → ?" because code read details.old_value/new_value but logTicketUpdate
stores the delta as {"status": {"from": ..., "to": ...}}.
base.css: move .is-hidden to base.css (global) — it was only defined in
ticket.css, so on the dashboard the ticket-preview popup had no hide
rule applied and was visible in the DOM at all times.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+16
-8
@@ -65,15 +65,16 @@ $assignRows = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
|
|||||||
$stmt->close();
|
$stmt->close();
|
||||||
|
|
||||||
// Query 2: Comments on tickets I own or watch (events from other users)
|
// Query 2: Comments on tickets I own or watch (events from other users)
|
||||||
|
// Comments are logged as action_type='create', entity_type='comment', with ticket_id in details JSON.
|
||||||
$commentSql = "SELECT DISTINCT
|
$commentSql = "SELECT DISTINCT
|
||||||
al.log_id, al.action_type, al.entity_type, al.entity_id, al.details, al.created_at,
|
al.log_id, al.action_type, al.entity_type, al.entity_id, al.details, al.created_at,
|
||||||
COALESCE(u.display_name, u.username, 'System') AS actor_name
|
COALESCE(u.display_name, u.username, 'System') AS actor_name
|
||||||
FROM audit_log al
|
FROM audit_log al
|
||||||
LEFT JOIN users u ON al.user_id = u.user_id
|
LEFT JOIN users u ON al.user_id = u.user_id
|
||||||
INNER JOIN tickets t ON t.ticket_id = CAST(al.entity_id AS UNSIGNED)
|
INNER JOIN tickets t ON t.ticket_id = CAST(JSON_UNQUOTE(JSON_EXTRACT(al.details, '$.ticket_id')) AS UNSIGNED)
|
||||||
LEFT JOIN ticket_watchers tw ON tw.ticket_id = t.ticket_id AND tw.user_id = ?
|
LEFT JOIN ticket_watchers tw ON tw.ticket_id = t.ticket_id AND tw.user_id = ?
|
||||||
WHERE al.action_type = 'comment'
|
WHERE al.action_type = 'create'
|
||||||
AND al.entity_type = 'ticket'
|
AND al.entity_type = 'comment'
|
||||||
AND al.user_id != ?
|
AND al.user_id != ?
|
||||||
AND al.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
AND al.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||||
AND (t.assigned_to = ? OR t.created_by = ? OR tw.user_id IS NOT NULL)
|
AND (t.assigned_to = ? OR t.created_by = ? OR tw.user_id IS NOT NULL)
|
||||||
@@ -123,16 +124,23 @@ $all = array_slice($all, 0, 30);
|
|||||||
$notifications = [];
|
$notifications = [];
|
||||||
foreach ($all as $row) {
|
foreach ($all as $row) {
|
||||||
$details = json_decode($row['details'] ?? '{}', true) ?? [];
|
$details = json_decode($row['details'] ?? '{}', true) ?? [];
|
||||||
$ticketId = (int)$row['entity_id'];
|
// Comment rows: entity_id is the comment_id; real ticket_id is in details
|
||||||
|
$actionType = ($row['action_type'] === 'create' && $row['entity_type'] === 'comment')
|
||||||
|
? 'comment'
|
||||||
|
: $row['action_type'];
|
||||||
|
$ticketId = ($actionType === 'comment')
|
||||||
|
? (int)($details['ticket_id'] ?? 0)
|
||||||
|
: (int)$row['entity_id'];
|
||||||
$isRead = $lastSeen && $row['created_at'] <= $lastSeen;
|
$isRead = $lastSeen && $row['created_at'] <= $lastSeen;
|
||||||
|
|
||||||
// Build human-readable title
|
// Build human-readable title
|
||||||
$title = match($row['action_type']) {
|
$title = match($actionType) {
|
||||||
'assign' => "{$row['actor_name']} assigned ticket #{$ticketId} to you",
|
'assign' => "{$row['actor_name']} assigned ticket #{$ticketId} to you",
|
||||||
'comment' => "{$row['actor_name']} commented on ticket #{$ticketId}",
|
'comment' => "{$row['actor_name']} commented on ticket #{$ticketId}",
|
||||||
'update' => (function() use ($row, $details, $ticketId) {
|
'update' => (function() use ($row, $details, $ticketId) {
|
||||||
$from = $details['old_value'] ?? '?';
|
// logTicketUpdate stores delta as {"status": {"from": "Open", "to": "In Progress"}}
|
||||||
$to = $details['new_value'] ?? '?';
|
$from = $details['status']['from'] ?? ($details['old_value'] ?? '?');
|
||||||
|
$to = $details['status']['to'] ?? ($details['new_value'] ?? '?');
|
||||||
return "{$row['actor_name']} changed status on #{$ticketId}: {$from} → {$to}";
|
return "{$row['actor_name']} changed status on #{$ticketId}: {$from} → {$to}";
|
||||||
})(),
|
})(),
|
||||||
default => "{$row['actor_name']} updated ticket #{$ticketId}",
|
default => "{$row['actor_name']} updated ticket #{$ticketId}",
|
||||||
@@ -149,7 +157,7 @@ foreach ($all as $row) {
|
|||||||
'title' => $title,
|
'title' => $title,
|
||||||
'created_at' => $row['created_at'],
|
'created_at' => $row['created_at'],
|
||||||
'is_read' => $isRead,
|
'is_read' => $isRead,
|
||||||
'action' => $row['action_type'],
|
'action' => $actionType,
|
||||||
'url' => "/ticket/{$ticketId}",
|
'url' => "/ticket/{$ticketId}",
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2341,6 +2341,7 @@ select option:checked {
|
|||||||
.lt-text-upper { text-transform: uppercase; letter-spacing: 0.1em; }
|
.lt-text-upper { text-transform: uppercase; letter-spacing: 0.1em; }
|
||||||
|
|
||||||
.lt-hidden { display: none !important; }
|
.lt-hidden { display: none !important; }
|
||||||
|
.is-hidden { display: none !important; }
|
||||||
|
|
||||||
/* Skip navigation link — visible only on focus */
|
/* Skip navigation link — visible only on focus */
|
||||||
.lt-skip-link {
|
.lt-skip-link {
|
||||||
|
|||||||
@@ -203,8 +203,7 @@ body.edit-mode .editable-metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── Visibility groups toggle ────────────────────────────────── */
|
/* ── Visibility groups toggle ────────────────────────────────── */
|
||||||
.ticket-visibility-groups.is-hidden,
|
.ticket-visibility-groups.is-hidden { display: none !important; }
|
||||||
.is-hidden { display: none !important; }
|
|
||||||
|
|
||||||
/* ── Page header utility ─────────────────────────────────────── */
|
/* ── Page header utility ─────────────────────────────────────── */
|
||||||
.lt-page-header {
|
.lt-page-header {
|
||||||
|
|||||||
Reference in New Issue
Block a user