fix: watcher avatars, dependency TDS styling, asset versions, nav dropdown light theme
- watch_ticket.php GET now returns watcher list (up to 6 users) for avatar group - TicketView: watcher avatar group rendered next to WATCH button, refreshes on toggle - Rewrite renderDependencies/renderDependents to use TDS lt-kv-grid/lt-badge/lt-btn classes - renderDependencies: show lt-alert--warning blocker banner when blocked_by has open tickets - Fix ALL hardcoded ?v=20260327 asset version strings in CreateTicketView + all admin views - base.css: fix .lt-nav-dropdown-menu hardcoded background → var(--bg-overlay) - base.css: add light-theme overrides for nav dropdown menu (background, links, hover) - ticket.css: add .lt-avatar-group and .lt-avatar--overflow styles for watcher display Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -163,6 +163,7 @@ include __DIR__ . '/layout_header.php';
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
</select>
|
||||
<span id="watcherAvatarGroup" class="lt-avatar-group lt-avatar-group--sm" aria-label="Watchers" style="display:none"></span>
|
||||
<button type="button" id="watchButton" class="lt-btn lt-btn-ghost lt-btn-sm"
|
||||
title="Watch this ticket to receive Matrix notifications on updates">WATCH</button>
|
||||
<button type="button" id="editButton" class="lt-btn lt-btn-primary lt-btn-sm">EDIT</button>
|
||||
@@ -868,6 +869,32 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
|
||||
// Watch / Unwatch button
|
||||
var watchBtn = document.getElementById('watchButton');
|
||||
var watcherGroup = document.getElementById('watcherAvatarGroup');
|
||||
|
||||
function _renderWatcherAvatars(watchers) {
|
||||
if (!watcherGroup) return;
|
||||
if (!watchers || !watchers.length) { watcherGroup.style.display = 'none'; return; }
|
||||
var avatarColors = ['lt-avatar--orange', 'lt-avatar--green', 'lt-avatar--purple', ''];
|
||||
var html = '';
|
||||
var shown = watchers.slice(0, 4);
|
||||
shown.forEach(function (w) {
|
||||
var words = (w.display_name || '').trim().split(/\s+/).filter(Boolean);
|
||||
var initials = words.slice(0, 2).map(function (x) { return x[0].toUpperCase(); }).join('');
|
||||
var hash = 0;
|
||||
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\'">' +
|
||||
'<span class="lt-avatar-initials">' + lt.escHtml(initials) + '</span>' +
|
||||
'</div>';
|
||||
});
|
||||
if (watchers.length > 4) {
|
||||
html += '<div class="lt-avatar lt-avatar--xs lt-avatar--overflow" title="' + (watchers.length - 4) + ' more watchers">+' + (watchers.length - 4) + '</div>';
|
||||
}
|
||||
watcherGroup.innerHTML = html;
|
||||
watcherGroup.style.display = 'flex';
|
||||
}
|
||||
|
||||
if (watchBtn) {
|
||||
var _watching = false;
|
||||
// Fetch initial state
|
||||
@@ -880,6 +907,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
? 'You are watching this ticket. Click to stop.'
|
||||
: 'Watch this ticket for Matrix notifications on updates.';
|
||||
if (_watching) watchBtn.classList.add('lt-btn-active');
|
||||
_renderWatcherAvatars(d.watchers || []);
|
||||
}
|
||||
})
|
||||
.catch(function () {});
|
||||
@@ -897,6 +925,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
: 'Watch this ticket for Matrix notifications on updates.';
|
||||
watchBtn.classList.toggle('lt-btn-active', _watching);
|
||||
lt.toast.success(_watching ? 'Watching ticket' : 'Stopped watching ticket');
|
||||
// Refresh watcher avatars from server
|
||||
lt.api.get('/api/watch_ticket.php?ticket_id=' + window.ticketData.ticket_id)
|
||||
.then(function (d2) { if (d2.success) _renderWatcherAvatars(d2.watchers || []); })
|
||||
.catch(function () {});
|
||||
} else {
|
||||
lt.toast.error('Failed: ' + (d.error || 'Unknown error'));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user