Azure DevOps Pull Request Filter

Filter pull Requests in Azure DevOps by tags

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Azure DevOps Pull Request Filter
// @namespace    https://github.com/calne-ca
// @version      0.2.1
// @description  Filter pull Requests in Azure DevOps by tags
// @author       Joscha Düringer
// @license      MIT
// @supportURL   https://github.com/calne-ca/tampermonkey-azure-devops-pull-request-tag-filter
// @match        https://dev.azure.com/*/pullrequests*
// @icon         https://www.google.com/s2/favicons?domain=dev.azure.com
// @grant        none
// ==/UserScript==

function removePullRequest(pullRequest){
    console.log("Removing pull request: " + pullRequest);
    pullRequest.remove();
}

function adjustRowSpacers() {
    const rowSpacers = document.getElementsByClassName('bolt-list-cell-spacer');

    for(const rowSpacer of rowSpacers){
        rowSpacer.style.height = 0;
    }
}

function stringMatchesFilter(str, filter) {
    return filter.some(filterStr=> new RegExp("^" + filterStr + "$").test(str));
}

function pullRequestHasMatchingTag(pullRequest, filteredTags, showUntagged) {
    if(filteredTags.length === 0) {
        return true;
    }

    const labels = pullRequest.querySelectorAll('.bolt-pill-overflow .text-ellipsis');
    const pullRequestLabels = []

    if(labels.length === 0 && showUntagged) {
        return true;
    }

    for (const label of labels) {
        pullRequestLabels.push(label.textContent);
    }

    return pullRequestLabels.some(tag=> stringMatchesFilter(tag, filteredTags));
}

function pullRequestHasMatchingTitle(pullRequest, filteredTitles) {
    if(filteredTitles.length === 0){
        return true;
    }

    const title = pullRequest.querySelector('.body-l').textContent;

    return stringMatchesFilter(title, filteredTitles);
}

function pullRequestHasAssignee(pullRequest){
    const assignees = pullRequest.querySelectorAll('.bolt-table-cell-content .flex-center img');
    return assignees.length > 0;
}

function pullRequestShouldBeRemoved(pullRequest, filteredTags, showUntagged, filteredTitles, unassignedOnly) {
    return !pullRequestHasMatchingTag(pullRequest, filteredTags, showUntagged) ||
        !pullRequestHasMatchingTitle(pullRequest, filteredTitles) ||
        (unassignedOnly && pullRequestHasAssignee(pullRequest));
}

function filterPullRequests(pullRequests, filteredTags, showUntagged, filteredTitles, unassignedOnly){
    for (const pullRequest of pullRequests) {
        if (pullRequestShouldBeRemoved(pullRequest, filteredTags, showUntagged, filteredTitles, unassignedOnly)) {
            removePullRequest(pullRequest)
        }
    }

    adjustRowSpacers();
}

(function() {
    'use strict';

    const urlParams = new URLSearchParams(window.location.search);
    const tagFilterParam = urlParams.get('tagFilter');
    const titleFilterParam = urlParams.get('titleFilter');
    const showUntaggedParam = urlParams.get('showUntagged');
    const unassignedOnlyParam = urlParams.get('unassignedOnly');
    const refreshInterval = 200;

    const filteredTags = tagFilterParam ? tagFilterParam.split(',') : [];
    const filteredTitles = titleFilterParam ? titleFilterParam.split(',') : [];
    const showUntagged = showUntaggedParam === 'true'
    const unassignedOnly = unassignedOnlyParam === 'true'

    if(filteredTags.length === 0 && filteredTitles.length === 0 && !unassignedOnly) {
        return;
    }

    console.log("Filtering pull requests with filteredTags='" + filteredTags + "', showUntagged='" + showUntagged + "', filteredTitles='" + filteredTitles + "', unassignedOnly='" + unassignedOnly + "'");

    setInterval(function() {
        const path = window.location.pathname.replace(/\/$/, "");

        if(!path.endsWith('pullrequests')) {
            return;
        }

        const pullRequests = document.getElementsByClassName('bolt-list-row');

        if (pullRequests) {
            filterPullRequests(pullRequests, filteredTags, showUntagged, filteredTitles, unassignedOnly);
        }
    }, refreshInterval);
})();