Azure DevOps Zendesk Link v1.2.0
← Back to User Scripts
Script Content
// ==UserScript==
// @name Azure DevOps Zendesk Link
// @namespace https://github.com/tjhleeds/user-scripts/
// @version 1.2.0
// @description Adds a button to Azure DevOps work items to open the corresponding Zendesk ticket.
// @author tjhleeds using Jules
// @match https://dev.azure.com/*
// @grant GM_openInTab
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
console.log('Zendesk Link script started');
const zendeskRegex = /\[Zendesk (\d+)\]/;
const zendeskIconSvg = `
`;
function addButtonToTitle(titleElement) {
console.log('addButtonToTitle called');
const match = titleElement.value.match(zendeskRegex);
if (!match) {
console.log('No Zendesk link found in title');
return;
}
const zendeskId = match[1];
const zendeskUrl = `https://audacia.zendesk.com/agent/tickets/${zendeskId}`;
// Check if button already exists
if (document.getElementById('zendesk-link-button')) {
console.log('Zendesk link button already exists');
return;
}
console.log(`Zendesk ticket ${zendeskId} found, adding button`);
const button = document.createElement('button');
button.id = 'zendesk-link-button';
button.innerHTML = zendeskIconSvg;
button.onclick = () => {
GM_openInTab(zendeskUrl, { active: true });
};
const titleElementParent = titleElement.parentElement;
titleElementParent.style.position = 'relative';
// Add padding to the title element to make space for the button
titleElement.style.paddingLeft = '40px';
GM_addStyle(`
#zendesk-link-button {
position: absolute;
left: 0px;
top: 50%;
transform: translateY(-50%);
width: 34px;
height: 34px;
z-index: 1000;
border: none;
background: transparent;
cursor: pointer;
padding: 3px;
}
#zendesk-link-button svg {
width: 100%;
height: 100%;
}
`);
titleElementParent.appendChild(button);
console.log('Zendesk link button added');
}
function addZendeskLinkToInlineItem(inlineLinkElement) {
console.log('addZendeskLinkToInlineItem called');
const wiData = JSON.parse(inlineLinkElement.dataset.wi);
const title = wiData[0].title;
const match = title.match(zendeskRegex);
if (!match) {
console.log('No Zendesk link found in inline item title');
return;
}
inlineLinkElement.dataset.zendeskLinkAdded = 'true';
const zendeskId = match[1];
const zendeskUrl = `https://audacia.zendesk.com/agent/tickets/${zendeskId}`;
console.log(`Zendesk ticket ${zendeskId} found, adding link`);
const zendeskLink = document.createElement('a');
zendeskLink.href = zendeskUrl;
zendeskLink.target = '_blank';
zendeskLink.innerHTML = zendeskIconSvg;
zendeskLink.classList.add('zendesk-inline-link');
inlineLinkElement.before(zendeskLink);
}
const observer = new MutationObserver(() => {
console.log('Mutation observer triggered');
const titleElement = document.querySelector('[aria-label="Title field"]');
if (titleElement) {
addButtonToTitle(titleElement);
} else {
console.log('Title element not found');
}
const inlineLinks = document.querySelectorAll('a[data-wi]:not([data-zendesk-link-added])');
inlineLinks.forEach(addZendeskLinkToInlineItem);
});
GM_addStyle(`
.zendesk-inline-link {
display: inline-block;
width: 16px;
height: 16px;
margin-right: 4px;
vertical-align: middle;
}
.zendesk-inline-link svg {
width: 100%;
height: 100%;
}
`);
console.log('Observing document for mutations');
observer.observe(document, {
childList: true,
subtree: true
});
})();