ECOD-Jira-List-Copier

Copy JIRA issues from sprints in one big list

当前为 2024-02-10 提交的版本,查看 最新版本

// ==UserScript==
// @name         ECOD-Jira-List-Copier
// @namespace    jira.list-copy
// @version      1.0.1
// @description  Copy JIRA issues from sprints in one big list
// @author       [email protected]
// @require      https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.6/underscore-umd-min.js
// @match        https://jira.fsc.atos-services.net/secure/RapidBoard.jspa?rapidView*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    function hookTheMonkeyForJira() {
        var scriptFunctionCopyList = document.createElement('script');
        scriptFunctionCopyList.innerText = `function copyList(node, $case) {
            let tiles =  node.parentNode.parentNode.parentNode.nextSibling.firstChild.childNodes;
            let listData = [];
            tiles.forEach(function (tile) {
                if(tile.attributes && tile.attributes['data-issue-key']){
                    let id = tile.attributes['data-issue-key'].value;
                    let issue = '?';
                    let type = '?';
                    let status = '?';
                    let priority = '?';
                    let link = '?';

                    if(tile.childNodes[0] && tile.childNodes[0].attributes && tile.childNodes[0].attributes['aria-label']){
                        issue = tile.childNodes[0].attributes['aria-label'].value;
                    }

                    if(tile.childNodes[1] && tile.childNodes[1].childNodes[0] && tile.childNodes[1].childNodes[0].childNodes[0] && tile.childNodes[1].childNodes[0].childNodes[0].attributes['title']){
                        type = tile.childNodes[1].childNodes[0].childNodes[0].attributes['title'].value;
                    }

                    if(tile.childNodes[1] && tile.childNodes[1].childNodes[0] && tile.childNodes[1].childNodes[0].childNodes[1] && tile.childNodes[1].childNodes[0].childNodes[1].childNodes[0].attributes['title']){
                        priority = tile.childNodes[1].childNodes[0].childNodes[1].childNodes[0].attributes['title'].value;
                    }

                    if(tile.childNodes[1] && tile.childNodes[1].childNodes[0] && tile.childNodes[1].childNodes[0].childNodes[2] && tile.childNodes[1].childNodes[0].childNodes[2].childNodes[0].attributes['href']){
                        link = 'https://jira.fsc.atos-services.net' + tile.childNodes[1].childNodes[0].childNodes[2].childNodes[0].attributes['href'].value;
                    }

                    if(tile.childNodes[1] && tile.childNodes[1].childNodes[1] && tile.childNodes[1].childNodes[1].childNodes[0] && tile.childNodes[1].childNodes[1].childNodes[0].childNodes[0]){
                        status = tile.childNodes[1].childNodes[1].childNodes[0].childNodes[0].innerText;
                    }

                    listData.push({'id': id, 'issue': issue, 'type': type, 'status': status, 'priority': priority, 'link': link});
                }
            });

            console.debug(listData);
            listData.sort((a, b) => {
                if (a.type < b.type) return -1;
                if (a.type > b.type) return 1;
                if (a.priority < b.priority) return -1;
                if (a.priority > b.priority) return 1;
                return 0;
            });

            clip = '';

            switch($case){
                case 'lines':
                   listData.forEach((row) => clip += '[' + row.type + '][' + row.priority + ']' +  row.issue + '\\r\\n');
                break;
                case 'csv':
                   listData.forEach((row) => clip += row.type + ';' + row.priority + ';' +  row.issue + ';' + row.status + ';' + row.link + '\\r\\n');
                break;
                default:
                    listData.forEach((row) => clip += '[' + row.type + '][' + row.priority + ']' +  row.issue + '\\r\\n');

            };

            navigator.clipboard.writeText(_.unescape(clip));
            node.className='monkeyButtons elementToFadeInAndOut';
            setTimeout(
                function(){
                    node.className='monkeyButtons';
                }, 500
            );
        }`;

        var style = document.createElement('style');
        style.innerText = `
        .elementToFadeInAndOut {
            animation: fadeInOut 0.5s linear forwards;
        }
        @keyframes fadeInOut {
            0% { opacity:0; }
            50% { opacity:0.5; }
            100% { opacity:1; }
        }
        .monkeyButtons {
            cursor:pointer;
            background-color: #0747a6;
            width: auto;
            border-radius: 4px;
            color: white;
            padding-left: 15px;
            padding-right: 15px;
            padding-top: 0px;
            padding-bottom: 0px;
            font-size: 11px
        }`;

        document.body.appendChild(scriptFunctionCopyList);
        document.body.appendChild(style);
    }

    function addButtonToNode(node) {
        function copyList($case){

        }

        var copyButton1 = document.createElement('span');
        copyButton1.setAttribute("style" ,"cursor:pointer; display: inline;");
        copyButton1.classList.add('ghx-sprint-info');
        copyButton1.innerHTML = `<span
                                     class='monkeyButtons'
                                     name='copyList'
                                     id='copyList'
                                     onclick='copyList(this, "lines");'
                                     title='Copy List!'>Copy list Text</span>`;

        var copyButton2 = document.createElement('span');
        copyButton2.setAttribute("style" ,"cursor:pointer; display: inline;");
        copyButton2.classList.add('ghx-sprint-info');
        copyButton2.innerHTML = `<span
                                     class='monkeyButtons'
                                     name='copyList'
                                     id='copyList'
                                     onclick='copyList(this, "csv");'
                                     title='Copy List!'>Copy list CSV</span>`;



        if(node) {
            let divContainer = document.createElement('div');
            divContainer.appendChild(copyButton1);
            divContainer.appendChild(copyButton2);
            //divContainer.setAttribute("style", "margin-top:10px; display: inline-block");

            node.firstChild.appendChild(divContainer);
        }
    }

    // Callback function to observe mutations in the DOM
    function handleJiraMutations(mutationsList, observer) {
        for (var mutation of mutationsList) {
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                mutation.addedNodes.forEach(function(node) {
                    //console.debug("NODE: ", node.attributes && node.attributes['data-sprint-id']);
                    if (node.attributes && node.attributes['data-sprint-id']) {
                        //console.debug("FOUND: " + node.id);
                        addButtonToNode(node);
                    }
                });
            }
        }
    }

    hookTheMonkeyForJira();
    // Create a new MutationObserver
    var boardObserver = new MutationObserver(handleJiraMutations);

    // Start observing the body for DOM changes
    boardObserver.observe(document.body, {
        childList: true,
        subtree: true
    });

})();