ECOD-JiraHelper-Copier

Jira ID + Title copy to clipboad feature with various formats. (Note: Jira View Workflow does not work with this extension)

Από την 11/02/2024. Δείτε την τελευταία έκδοση.

// ==UserScript==
// @name         ECOD-JiraHelper-Copier
// @namespace    ecod.jira.copier
// @version      1.8.2
// @description  Jira ID + Title copy to clipboad feature with various formats. (Note: Jira View Workflow does not work with this extension)
// @author       CRK
// @require      https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js
// @match        https://*jira.fsc.atos-services.net/browse/*
// @match        https://*jira.fsc.atos-services.net/secure/RapidBoard.jspa*
// @match        https://*jira.fsc.atos-services.net/projects/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    function hookTheJiraMonkey() {
        var copyIdButton = document.createElement('span');
        copyIdButton.innerHTML = `<span class='monkeyButtons'
                                       style='cursor:pointer; background-color: #0747a6; width: 20px;'
                                       id='copyId'
                                       name='copyId'
                                       onclick='copyToClipboard(this, "id");'
                                       title='Copy ID'>ID</span>`;

        var copyToClipboardButton = document.createElement('span');
        copyToClipboardButton.innerHTML = `<span class='monkeyButtons'
                                        style='cursor:pointer; background-color: #0747a6; width: 25px;'
                                        id='copyToClipboard'
                                        name='copyToClipboard'
                                        onclick='copyToClipboard(this);'
                                        title='Copy ID + Title!'>ID+</span>`;

        var copyToClipboard4BranchButton = document.createElement('span');
        copyToClipboard4BranchButton.innerHTML = `<span class='monkeyButtons'
                                               style='cursor:pointer; background-color: blue;'
                                               id='copyToClipboard4Branch'
                                               name='copyToClipboard4Branch'
                                               onclick='copyToClipboard(this, "branch");'
                                               title='Copy ID + Title (branch)'>Branch</span>`;

        var copyToClipboard4CommitButton = document.createElement('span');
        copyToClipboard4CommitButton.innerHTML = `<span class='monkeyButtons'
                                               style='cursor:pointer; background-color: blue;'
                                               id='copyToClipboard4Commit'
                                               name='copyToClipboard4Commit'
                                               onclick='copyToClipboard(this, "commit");'
                                               title='Copy ID + Title (branch)'>Commit</span>`;

        var copyToClipboard4MergeButton = document.createElement('span');
        copyToClipboard4MergeButton.innerHTML = `<span class='monkeyButtons'
                                            style='cursor:pointer; background-color: blue;'
                                            id='copyToClipboard4Git'
                                            name='copyToClipboard4Git'
                                            onclick='copyToClipboard(this, "merge");'
                                            title='Copy ID + Title (GIT)'>Merge</span>`;
        var gotoGitLabButton = document.createElement('span');
        gotoGitLabButton.innerHTML = `<span
                                           class='monkeyButtons'
                                           style='cursor:pointer; background-color: #5707a6; width: 60px;'
                                           name='gotoGitLab'
                                           id='gotoGitLab'
                                           onclick='goToUrl(this);'
                                           title='Go to Gitlab Merge request'>Goto MR</span>`;

        var shareLinkButton = document.createElement('span');
        shareLinkButton.innerHTML = `<span
                                           class='monkeyButtons'
                                           style='cursor:pointer; cursor:pointer; background-color: green; width: 30px; padding: 7px;'
                                           name='shareLink'
                                           id='shareLink'
                                           onclick='copyToClipboard(this, "share");'
                                           title='Sharable link'><span class="icon aui-icon aui-icon-small aui-iconfont-share"></span></span>`;


        var scriptFunctioncopyToClipboard = document.createElement('script');
        scriptFunctioncopyToClipboard.innerText = `
        function copyToClipboard(el, option) {
            let id = document?.querySelector(\"a[id='key-val']\")?.innerHTML?.trim() ?? 'unknown';
            if(id === 'unknown'){
                id = el?.parentNode?.parentNode?.parentNode?.querySelector(\"[class='ghx-key js-view-in-jira']\")?.innerText?.trim() ?? 'unknown';
            }
            id = _.deburr(_.unescape(id.trim()));

            let text4Clipboard = id;

            if(option !== 'id') {
                let title = document?.querySelector(\"h1[id='summary-val']\")?.innerHTML?.trim()?.split('<span')[0] ?? 'unknown';
                if(title === 'unknown'){
                    title = el?.parentNode?.parentNode?.parentNode?.querySelector(\"dd[id='summary-val']\")?.innerText?.trim() ?? 'unknown';
                }
                title = _.deburr(_.unescape(title.trim()));

                text4Clipboard += ' ' + title;

                if(['branch', 'commit', 'merge'].includes(option)) {
                    let type = document.querySelector(\"span[id='type-val']\").innerHTML.trim().split('<span')[0].split('">')[1].trim();
                    let typeBranch = 'feature';

                    switch (type) {
                        case 'Task':
                        case 'Story':
                            type = 'feat';
                            typeBranch = 'feature';
                            break;
                        case 'Bug':
                            type = 'fix';
                            typeBranch = 'bugfix';
                            break;
                        default:
                            type = 'feat';
                            break;
                    };

                    if(option === 'branch') {
                        text4Clipboard = typeBranch + '/' + id.toLowerCase() + '_' + title.replace(/[^a-zA-Z0-9]+/g, \"_\").toLowerCase().replace(/_+$/, '');
                    }

                    if(option === 'commit') {
                        text4Clipboard = type + '(' + id.toLowerCase() + ')' + ': ' + title.replace(/[^a-zA-Z0-9]+/g, \"_\").toLowerCase().replace(/_+$/, '');
                    }

                    if(option === 'merge') {
                        text4Clipboard = type + '(' + id.toLowerCase() + ')' + ': ' + title;
                    }
                }

                if(option === 'share') {
                        let linkText = id.toUpperCase() + ' ' + title.trim();
                        let linkUrl = 'https://jira.fsc.atos-services.net/browse/' + id.toUpperCase();
                        text4Clipboard = '[' + linkText + ']( ' + linkUrl + ' )';
                }
            }

            navigator.clipboard.writeText(text4Clipboard);
            el.className='monkeyButtons elementToFadeInAndOut';
            setTimeout(
                function(){
                    el.className='monkeyButtons';
                }, 500
            );
    }

    function goToUrl(el){
    	let baseUrl = 'https://gitlab.ecodesigncloud.com/groups/ecodesign/-/merge_requests?scope=all&state=all&search=';
        let id = document?.querySelector(\"a[id='key-val']\")?.innerHTML?.trim() ?? 'unknown';
        if(id === 'unknown'){
            id = el?.parentNode?.parentNode?.parentNode?.querySelector(\"[class='ghx-key js-view-in-jira']\")?.innerText?.trim() ?? 'unknown';
        }
        if(id !== 'unknown'){
    	    window.open(baseUrl + id, '_blank');
        } else {
            el.setStyle('background-color', 'gray');
        }
    }`;

        var style = document.createElement('style');
        style.innerText = `
        .jiraButtons {
            border-radius: 4px;
            padding: 10px;
            margin-left:10px;
            color:white;
            font-weight:bold;
            border:0;
            font-size: 14px;
            width: 10%;
            justify-content: center;
        }
        .elementToFadeInAndOut {
            animation: fadeInOut 0.5s linear forwards;
        }
        @keyframes fadeInOut {
            0% { opacity:0; }
            50% { opacity:0.5; }
            100% { opacity:1; }
        }
        .monkeyButtons {
            display: inline-flex;
            border-radius: 5px;
            padding: 5px;
            color:white;
            font-weight:normal;
            border:0;
            font-size:14px;
            width: 50px;
            justify-content: center;
            margin-left: 6px
        }`;

        document.body.appendChild(scriptFunctioncopyToClipboard);
        document.body.appendChild(style);

        let node = document.querySelector('#opsbar-transitions_more')
        if(node) {
            let divContainer = document.createElement('div');
            divContainer.appendChild(copyIdButton);
            divContainer.appendChild(copyToClipboardButton);
            divContainer.appendChild(copyToClipboard4BranchButton);
            divContainer.appendChild(copyToClipboard4CommitButton);
            divContainer.appendChild(copyToClipboard4MergeButton);
            divContainer.appendChild(gotoGitLabButton);
            divContainer.appendChild(shareLinkButton);

            divContainer.setAttribute("class", "aui-buttons pluggable-ops");
            divContainer.setAttribute("style", "margin-top:10px;");

            node.parentNode.appendChild(divContainer);
        }
    }

    function injectButtonsToNode(node) {
        if (node) {
            let copyIdButton = document.createElement('span');
            copyIdButton.innerHTML = `<span
                                          class='monkeyButtons'
                                          style='cursor:pointer; background-color: #0747a6; width: 20px;'
                                          name='copyId'
                                          id='copyId'
                                          onclick='copyToClipboard(this, "id");'
                                          title='Copy ID only!'>ID</span>`;

            let copyToClipboardButton = document.createElement('span');
            copyToClipboardButton.innerHTML = `<span
                                           class='monkeyButtons'
                                           style='cursor:pointer; background-color: #0747a6; width: 25px;'
                                           name='copyToClipboard'
                                           id='copyToClipboard'
                                           onclick='copyToClipboard(this);'
                                           title='Copy ID + Title!'>ID+</span>`;

            let copyToClipboard4BranchButton = document.createElement('span');
            copyToClipboard4BranchButton.innerHTML = `<span
                                                   class='monkeyButtons'
                                                   style='cursor:pointer; background-color: blue;'
                                                   name='copyToClipboard4Branch'
                                                   id='copyToClipboard4Branch'
                                                   onclick='copyToClipboard(this, "branch");'
                                                   title='ID + Title for Branch'>Branch</span>`;

            let copyToClipboard4CommitButton = document.createElement('span');
            copyToClipboard4CommitButton.innerHTML = `<span
                                               class='monkeyButtons'
                                               style='cursor:pointer; background-color: blue;'
                                               name='copyToClipboard4Commit'
                                               id='copyToClipboard4Commit'
                                               onclick='copyToClipboard(this, "commit");'
                                               title='ID + Title for Commit'>Commit</span>`;

            let copyToClipboard4MergeButton = document.createElement('span');
            copyToClipboard4MergeButton.innerHTML = `<span
                                               class='monkeyButtons'
                                               style='cursor:pointer; background-color: blue;'
                                               name='copyToClipboard4Merge'
                                               id='copyToClipboard4Merge'
                                               onclick='copyToClipboard(this, "merge");'
                                               title='ID + Title for Merge'>Merge</span>`;

            let gotoGitLabButton = document.createElement('span');
            gotoGitLabButton.innerHTML = `<span
                                               class='monkeyButtons'
                                               style='cursor:pointer; background-color: #5707a6; width: 60px;'
                                               name='gotoGitLab'
                                               id='gotoGitLab'
                                               onclick='goToUrl(this);'
                                               title='Go to Gitlab Merge request'>Goto MR</span>`;

            let shareLinkButton = document.createElement('span');
            shareLinkButton.innerHTML = `<span
                                               class='monkeyButtons'
                                               style='cursor:pointer; background-color: green; width: 30px; padding: 7px;'
                                               name='shareLink'
                                               id='shareLink'
                                               onclick='copyToClipboard(this, "share");'
                                               title='Sharable link'><span class="icon aui-icon aui-icon-small aui-iconfont-share"></span></span>`;

            let divContainer = document.createElement('div');
            divContainer.appendChild(copyIdButton);
            divContainer.appendChild(copyToClipboardButton);
            if(node.id !== 'ghx-detail-issue'){
                divContainer.appendChild(copyToClipboard4BranchButton);
                divContainer.appendChild(copyToClipboard4CommitButton);
                divContainer.appendChild(copyToClipboard4MergeButton);
            }
            divContainer.appendChild(gotoGitLabButton);
            divContainer.appendChild(shareLinkButton);

            divContainer.setAttribute("class", "aui-buttons pluggable-ops");

            //backlog
            if(node.id === 'ghx-detail-issue' && node.firstChild){
                divContainer.setAttribute("style", "margin-top: 10px; margin-left: 45px;");
                node.insertBefore(divContainer, node.firstChild);
            }

            //issues
            if(node.id === 'stalker'){
                divContainer.setAttribute("style", "margin-bottom:10px; margin-left: 14px;");
                node.appendChild(divContainer);
            }

            //dedicated issue page (browse)
            if(node.id === 'opsbar-transitions_more') {
                divContainer.setAttribute("style", "margin-top:10px;");
                node.parentNode.appendChild(divContainer);
            }
        }
    }

    // Callback function to observe mutations in the DOM
    function handleDomMutations(mutationsList, observer) {
        for (var mutation of mutationsList) {
            // Check if nodes were added to the DOM
            //console.debug('mutation.type', mutation.type)
            if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                // Loop through the added nodes and check if any of them contain the modal content
                mutation.addedNodes.forEach(function(node) {
                    //console.debug("NODE: ", node.id);
                    if (node && (node.id === 'opsbar-transitions_more' || node.id === 'stalker' || node.id === 'ghx-detail-issue')) { // Replace with the actual ID of the modal container
                        // Call the function to add the button to the modal
                        //console.debug("FOUND: ", node.id);
                        injectButtonsToNode(node);
                    }
                });
            }
        }
    }

    hookTheJiraMonkey();

    // Create a new MutationObserver
    var domObserver = new MutationObserver(handleDomMutations);

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