Zendesk View Agent Name latest version (currently v1.0.0)
← Back to User Scripts
Script Content
// ==UserScript==
// @name Zendesk: View Agent Name
// @namespace https://www.timhilton.xyz/user-scripts
// @version 1.0.0
// @description Displays the first name of agents below their avatar in the agent collision viewer list.
// @author Tim Hilton using GitHub Copilot
// @match https://*.zendesk.com/agent/tickets/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
const LOG_PREFIX = '[Zendesk: View Agent Name]';
let observerFireCount = 0;
console.debug(`${LOG_PREFIX} Script initialised`);
// Add styles for the name labels
const style = document.createElement('style');
style.textContent = `
.agent-name-label {
position: absolute;
bottom: -20px;
left: 50%;
transform: translateX(-50%);
background: green;
color: white;
text-align: center;
padding: 2px 6px;
font-size: 11px;
white-space: nowrap;
border-radius: 2px;
z-index: 1000;
}
#agentCollisionViewerList li {
position: relative;
}
`;
document.head.appendChild(style);
let listObserver = null;
let documentObserver = null;
// Process collision avatars and add name labels
function processCollisionAvatars() {
console.debug(`${LOG_PREFIX} Processing collision avatars`);
const buttons = document.querySelectorAll('#agentCollisionViewerList button[data-test-id="collision-avatar"]');
console.debug(`${LOG_PREFIX} Found ${buttons.length} collision avatar button(s)`);
let processedCount = 0;
buttons.forEach(button => {
// Check if we've already processed this button
if (button.dataset.nameProcessed === 'true') {
return;
}
const ariaLabel = button.getAttribute('aria-label');
if (!ariaLabel) {
console.debug(`${LOG_PREFIX} Button has no aria-label, skipping`);
return;
}
// Extract the first word (first name) from the aria-label
const firstName = ariaLabel.trim().split(/\s+/)[0];
if (!firstName) {
console.debug(`${LOG_PREFIX} Could not extract first name from aria-label: "${ariaLabel}"`);
return;
}
console.debug(`${LOG_PREFIX} Extracted first name: "${firstName}" from aria-label: "${ariaLabel}"`);
// Find the parent li element
const parentLi = button.closest('li');
if (!parentLi) {
console.debug(`${LOG_PREFIX} Could not find parent li element`);
return;
}
// Remove any existing label
const existingLabel = parentLi.querySelector('.agent-name-label');
if (existingLabel) {
existingLabel.remove();
}
// Create and add the name label
const nameLabel = document.createElement('div');
nameLabel.className = 'agent-name-label';
nameLabel.textContent = firstName;
parentLi.appendChild(nameLabel);
// Mark as processed
button.dataset.nameProcessed = 'true';
processedCount++;
console.debug(`${LOG_PREFIX} Added name label for: ${firstName}`);
});
if (processedCount > 0) {
console.log(`${LOG_PREFIX} ✅ Successfully added ${processedCount} name label(s)`);
}
}
// Observe mutations within the agentCollisionViewerList
function observeList() {
console.debug(`${LOG_PREFIX} Entering observeList()`);
const list = document.getElementById('agentCollisionViewerList');
if (!list) {
console.debug(`${LOG_PREFIX} agentCollisionViewerList not found, exiting`);
return;
}
console.debug(`${LOG_PREFIX} agentCollisionViewerList found, processing existing avatars`);
// Process existing avatars
processCollisionAvatars();
// Create observer for the list
if (listObserver) {
console.debug(`${LOG_PREFIX} Disconnecting existing list observer`);
listObserver.disconnect();
}
listObserver = new MutationObserver((mutations) => {
observerFireCount++;
console.debug(`${LOG_PREFIX} List MutationObserver fired (count: ${observerFireCount})`);
let shouldProcess = false;
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// Check if buttons were added or removed
if (mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0) {
console.debug(`${LOG_PREFIX} childList mutation detected: ${mutation.addedNodes.length} added, ${mutation.removedNodes.length} removed`);
shouldProcess = true;
break;
}
} else if (mutation.type === 'attributes' && mutation.attributeName === 'aria-label') {
// If aria-label changes, we need to reprocess
console.debug(`${LOG_PREFIX} aria-label attribute changed`);
shouldProcess = true;
break;
}
}
if (shouldProcess) {
console.debug(`${LOG_PREFIX} Mutations require reprocessing`);
processCollisionAvatars();
} else {
console.debug(`${LOG_PREFIX} No relevant mutations, skipping reprocessing`);
}
});
listObserver.observe(list, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['aria-label']
});
console.debug(`${LOG_PREFIX} Now observing agentCollisionViewerList for mutations`);
}
// Observe the document for when agentCollisionViewerList appears
function observeDocument() {
console.debug(`${LOG_PREFIX} Entering observeDocument()`);
if (documentObserver) {
console.debug(`${LOG_PREFIX} Disconnecting existing document observer`);
documentObserver.disconnect();
}
documentObserver = new MutationObserver((mutations) => {
console.debug(`${LOG_PREFIX} Document MutationObserver fired`);
const list = document.getElementById('agentCollisionViewerList');
if (list) {
// Found the list, stop observing document
console.debug(`${LOG_PREFIX} agentCollisionViewerList appeared in DOM`);
documentObserver.disconnect();
// Start observing the list
observeList();
// Also observe for when the list disappears
observeListDisappearance();
}
});
documentObserver.observe(document.body, {
childList: true,
subtree: true
});
console.debug(`${LOG_PREFIX} Now observing document.body for agentCollisionViewerList`);
// Check if the list already exists
const list = document.getElementById('agentCollisionViewerList');
if (list) {
console.debug(`${LOG_PREFIX} agentCollisionViewerList already exists in DOM`);
documentObserver.disconnect();
observeList();
observeListDisappearance();
} else {
console.debug(`${LOG_PREFIX} agentCollisionViewerList not yet in DOM, waiting for it to appear`);
}
}
// Observe for when the list disappears
function observeListDisappearance() {
console.debug(`${LOG_PREFIX} Setting up disappearance observer`);
const disappearanceObserver = new MutationObserver((mutations) => {
console.debug(`${LOG_PREFIX} Disappearance MutationObserver fired`);
const list = document.getElementById('agentCollisionViewerList');
if (!list) {
// List has disappeared
console.debug(`${LOG_PREFIX} agentCollisionViewerList has disappeared from DOM`);
// Stop all observers
if (listObserver) {
console.debug(`${LOG_PREFIX} Disconnecting list observer`);
listObserver.disconnect();
listObserver = null;
}
disappearanceObserver.disconnect();
// Resume observing the document
console.debug(`${LOG_PREFIX} Resuming document observation`);
observeDocument();
}
});
disappearanceObserver.observe(document.body, {
childList: true,
subtree: true
});
console.debug(`${LOG_PREFIX} Disappearance observer active`);
}
// Initialise
console.debug(`${LOG_PREFIX} Starting initialisation`);
observeDocument();
console.log(`${LOG_PREFIX} 🎉 Script ready and monitoring for agent collision list`);
})();