|
1 | 1 | // ==UserScript== |
2 | 2 |
|
3 | 3 | // @name More Awesome Azure DevOps (userscript) |
4 | | -// @version 3.7.5 |
| 4 | +// @version 3.8.0 |
5 | 5 | // @author Alejandro Barreto (NI) |
6 | 6 | // @description Makes general improvements to the Azure DevOps experience, particularly around pull requests. Also contains workflow improvements for NI engineers. |
7 | 7 | // @license MIT |
|
972 | 972 | }`); |
973 | 973 |
|
974 | 974 | function watchForWorkItemForms() { |
975 | | - eus.globalSession.onEveryNew(document, '.menu-item.follow-item-menu-item-gray', followButton => { |
| 975 | + eus.globalSession.onEveryNew(document, '#__bolt-follow', followButton => { |
976 | 976 | followButton.addEventListener('click', async _ => { |
977 | | - await eus.sleep(100); // We need to allow the other handlers to send the request to follow/unfollow. After the request is sent, we can annotate our follows list correctly. |
978 | | - await annotateWorkItemWithFollowerList(document.querySelector('.discussion-messages-right')); |
| 977 | + await eus.sleep(1000); // We need to allow the other handlers to send the request to follow/unfollow. After the request is sent, we can annotate our follows list correctly. |
| 978 | + await annotateWorkItemWithFollowerList(document.querySelector('.comment-editor.enter-new-comment')); |
979 | 979 | }); |
980 | 980 | }); |
981 | 981 | // Annotate work items (under the comment box) with who is following it. |
982 | | - eus.globalSession.onEveryNew(document, '.discussion-messages-right', async commentEditor => { |
| 982 | + eus.globalSession.onEveryNew(document, '.comment-editor.enter-new-comment', async commentEditor => { |
983 | 983 | await annotateWorkItemWithFollowerList(commentEditor); |
984 | 984 | }); |
985 | 985 | } |
986 | 986 |
|
987 | 987 | async function annotateWorkItemWithFollowerList(commentEditor) { |
988 | | - document.querySelectorAll('.work-item-followers-list').forEach(e => e.remove()); |
| 988 | + const commentEditorContainer = commentEditor.closest('.new-comment-div'); |
| 989 | + commentEditorContainer.querySelectorAll('.work-item-followers-list').forEach(e => e.remove()); |
989 | 990 |
|
990 | | - const workItemId = commentEditor.closest('.witform-layout').querySelector('.work-item-form-id > span').innerText; |
991 | | - const queryResponse = await fetch(`${azdoApiBaseUrl}/_apis/notification/subscriptionquery?api-version=6.0`, { |
| 991 | + const workItemId = getCurrentWorkItemId(commentEditor); |
| 992 | + const queryResponse = await fetch(`${azdoApiBaseUrl}_apis/notification/subscriptionquery?api-version=6.0`, { |
992 | 993 | method: 'POST', |
993 | 994 | headers: { |
994 | 995 | 'Content-Type': 'application/json', |
|
1007 | 1008 | queryFlags: 'alwaysReturnBasicInformation', |
1008 | 1009 | }), |
1009 | 1010 | }); |
1010 | | - |
1011 | 1011 | const followers = [...(await queryResponse.json()).value].sort((a, b) => a.subscriber.displayName.localeCompare(b.subscriber.displayName)); |
1012 | 1012 | const followerList = followers |
1013 | | - .map(s => `<a href="mailto:${s.subscriber.uniqueName}">${s.subscriber.displayName}</a>`) |
1014 | | - .join(', ') |
1015 | | - || 'Nobody'; |
| 1013 | + .map(s => `<a class="bolt-link no-underline-link" target="_blank" href="https://teams.microsoft.com/l/chat/0/0?users=${s.subscriber.uniqueName}">${s.subscriber.displayName}</a>`) |
| 1014 | + .join(', '); |
| 1015 | + if (followerList) { |
| 1016 | + const annotation = `<div class="work-item-followers-list" style="margin: 1em 0em; opacity: 0.7"><span class="menu-item-icon bowtie-icon bowtie-watch-eye-fill" aria-hidden="true"></span> ${followerList}</div>`; |
| 1017 | + commentEditor.insertAdjacentHTML('afterend', annotation); |
| 1018 | + } |
| 1019 | + } |
| 1020 | + |
| 1021 | + function getCurrentWorkItemId(commentEditor) { |
| 1022 | + // Try getting the link from the work item header, in case this is opened in preview view |
| 1023 | + const workItemPage = commentEditor.closest('.work-item-form-page'); |
| 1024 | + const header = workItemPage.querySelector('.work-item-form-header'); |
| 1025 | + const links = header.querySelectorAll('a'); |
| 1026 | + // Loop through the links and check if their target matches a link for a work item |
| 1027 | + const workItemLink = Array.from(links).find(link => link.href.includes('_workitems')); |
| 1028 | + |
| 1029 | + // Default to the window URL if the find operation fails |
| 1030 | + let currentUrl = window.location.href; |
| 1031 | + if (workItemLink) { |
| 1032 | + currentUrl = workItemLink.href; |
| 1033 | + } |
| 1034 | + |
| 1035 | + const [baseUrl] = currentUrl.split('?'); |
| 1036 | + const urlSegments = baseUrl.split('/'); |
| 1037 | + const workItemId = urlSegments[urlSegments.length - 1]; |
1016 | 1038 |
|
1017 | | - const annotation = `<div class="work-item-followers-list" style="margin: 1em 0em; opacity: 0.8"><span class="menu-item-icon bowtie-icon bowtie-watch-eye-fill" aria-hidden="true"></span> ${followerList}</div>`; |
1018 | | - commentEditor.insertAdjacentHTML('BeforeEnd', annotation); |
| 1039 | + return workItemId; |
1019 | 1040 | } |
1020 | 1041 |
|
1021 | 1042 | function watchForRepoBrowsingPages(session) { |
|
0 commit comments