diff --git a/README.md b/README.md index 48700b5..0b7f63f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ By default, Violentmonkey will auto-update scripts from the original install loc - Reviews show build status (if it's empty, there isn't a merge commit or a build configured) - If a PR has bug work items associated with it, we add a label with the severity of such bugs (if SEV == 1 or 2) - Repo pull request listings will also link to the overall account-wide PR dashboard +- Each PR is annotated with source branch name. +- Target branch is hidden for PRs targeting `main` or `master`. +- Source and/or target branch name are abbreviated if they start with `users//`. - At [NI](https://www.ni.com), some labels get coloring (e.g. "bypass owners" gets a red background) - At [NI](https://www.ni.com), reviews are annotated with how long you've been on it if it's been over 1 weekday and you haven't voted or commented diff --git a/src/azdo-pr-dashboard.user.js b/src/azdo-pr-dashboard.user.js index e4a76bf..5768c5f 100644 --- a/src/azdo-pr-dashboard.user.js +++ b/src/azdo-pr-dashboard.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name More Awesome Azure DevOps (userscript) -// @version 3.8.2 +// @version 3.9.0 // @author Alejandro Barreto (NI) // @description Makes general improvements to the Azure DevOps experience, particularly around pull requests. Also contains workflow improvements for NI engineers. // @license MIT @@ -76,10 +76,13 @@ 'agent-arbitration-status-off': 'Off', }); - eus.showTipOnce('release-2026-04-15', 'New in the AzDO userscript', ` -

Highlights from the 2026-04-15 update!

+ eus.showTipOnce('release-2026-04-16', 'New in the AzDO userscript', ` +

Highlights from the 2026-04-16 update!

+

Changes to the PR dashboard view:

Comments, bugs, suggestions? File an issue on GitHub 🧡

`); @@ -1251,6 +1254,11 @@ .swal2-html-container { text-align: left; } + .swal2-html-container code { + background-color: rgba(0,0,0,.06); + padding: 0.2em 0.4em; + border-radius: 0.2em; + } .swal2-html-container li { list-style: disc; margin-left: 4ch; @@ -1499,6 +1507,7 @@ await annotateBugsOnPullRequestRow(row, pr); await annotateFileCountOnPullRequestRow(row, pr); await annotateBuildStatusOnPullRequestRow(row, pr); + annotateSourceBranchOnPullRequestRow(row, pr); if (votes.userVote === 0 && votes.missingVotes === 1 && votes.userIsRequired && !votes.userHasDeclined) { annotatePullRequestTitle(row, 'repos-pr-list-late-review-pill', 'Last Reviewer', 'Everyone is waiting on you!'); @@ -1519,6 +1528,7 @@ await annotateBugsOnPullRequestRow(row, pr); await annotateFileCountOnPullRequestRow(row, pr); await annotateBuildStatusOnPullRequestRow(row, pr); + annotateSourceBranchOnPullRequestRow(row, pr); } } @@ -1669,6 +1679,41 @@ annotatePullRequestLabel(row, 'build-status', tooltip, label); } + function annotateSourceBranchOnPullRequestRow(row, pr) { + if (!pr.lastMergeCommit) return; + + let sourceBranch = pr.sourceRefName.replace(/^refs\/heads\//, ''); + // Abbreviate e.g. 'users/kroeschl/foo' as '👤/foo' to save space + sourceBranch = sourceBranch.replace(/^users\/[^/]+\//, '/'); + let sourceBranchIcon = ''; + // Weird margin/padding to make this inline with the text + const userIcon = ''; + if (sourceBranch.startsWith('/')) { + sourceBranchIcon = userIcon; + } + + const secondary = row.querySelector('.secondary-text span'); + if (['refs/heads/master', 'refs/heads/main'].includes(pr.targetRefName)) { + // Hide target branch and icon if it's main or master, which is very common + secondary.querySelector('.ms-Icon--OpenSource').remove(); // Branch icon + secondary.querySelector('.monospaced-xs').remove(); // Branch name + secondary.innerHTML = secondary.innerHTML.replace('into ', ''); + } else { + const targetBranch = pr.targetRefName.replace(/^refs\/heads\//, ''); + const targetBranchAbbrev = targetBranch.replace(/^users\/[^/]+\//, '/'); + const targetBranchElement = secondary.querySelector('.monospaced-xs'); + targetBranchElement.innerHTML = targetBranchElement.innerHTML.replace(targetBranch, targetBranchAbbrev); + if (targetBranchAbbrev.startsWith('/')) { + targetBranchElement.insertAdjacentHTML('beforebegin', userIcon); + } + } + + const sourceBranchAnnotation = `from + ${sourceBranchIcon}${sourceBranch}`; + secondary.insertAdjacentHTML('beforeend', sourceBranchAnnotation); + } + function annotatePullRequestTitle(row, cssClass, message, tooltip) { const blockingAnnotation = `