floodmeadows / Jira create follow-on task

// ==UserScript==
// @name         Jira create follow-on task
// @namespace    https://openuserjs.org/users/floodmeadows
// @description  Adds button to create a linked BA task to send QA screenshots to the Welsh Language Team for their QA feedback. The name of the new BA task will be based on the name of the current dev story and will have a "relates to" link to the dev story.
// @copyright    2021, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license      MIT
// @version      0.3
// @include      https://jira.*.uk/browse/*
// @updateURL    https://openuserjs.org/meta/floodmeadows/Jira_create_follow-on_task.meta.js
// @downloadURL  https://openuserjs.org/install/floodmeadows/Jira_create_follow-on_task.user.js
// @grant        none
// ==/UserScript==

/* jshint esversion: 6 */

//--- Customise these to your Jira project ----//
const phraseToAppendToNewStoryName = " - Follow-on task";
const newIssueDefaultDescription = "Default text for new story details.";
const jiraTaskIssueTypeId = 3;
const customFieldForEpicLink = "customfield_10008"; // see https://stackoverflow.com/questions/24385644/jira-api-get-epic-for-issue
//---------------------------------------------//

const debug = false;

(function () {
    'use strict';

    addButton();
})();

function addButton() {
    const newElement = document.createElement("a");
    newElement.setAttribute("href", "#");
    newElement.setAttribute("class", "aui-button toolbar-trigger issueaction-workflow-transition");
    newElement.addEventListener("click", function () { createIssue() });
    const text = document.createTextNode("Add Follow-on Task");
    newElement.appendChild(text);
    //  const target = document.getElementById('opsbar-transitions_more').parentNode;
    const target = document.getElementById('opsbar-opsbar-admin');
    target.appendChild(newElement);
}

function createIssue() {
    //--- Get standard info ---//
    const currentUrl = new URL(document.URL);
    const jiraBaseUrl = currentUrl.protocol + '//' + currentUrl.host;
    const createIssueUrl = jiraBaseUrl + '/rest/api/latest/issue';
    const addLinkUrl = jiraBaseUrl + '/rest/api/latest/issueLink';

    // Parse the Jira project key out of the current URL. e.g. if the current issue key is "ABC-1234" then the project key will be ABC.
    const pathArr = location.pathname.split("/");
    const jiraProjectKey = pathArr[pathArr.length-1].split("-")[0];

    const currentIssueKey = document.getElementById("key-val").childNodes[0].nodeValue;
    const currentIssueSummary = document.getElementById("summary-val").childNodes[0].nodeValue;
    const epicLink = document.getElementById(`${customFieldForEpicLink}-val`).children[0].attributes.href.nodeValue.substring(8)
//    const updateIssueUrl = jiraBaseUrl + '/rest/api/latest/{issueIdOrKey}/transitions'; // actual URL is specified just before it is used, once we know the key

    var headers = new Headers();
    headers.append("Content-Type", "application/json");

    const newIssueSummary = currentIssueSummary + phraseToAppendToNewStoryName;

    var jsonToCreateNewIssue = "";
    jsonToCreateNewIssue = JSON.stringify({
        "fields": {
            "project": {
                "key": jiraProjectKey
            },
            "summary": newIssueSummary,
            "description": newIssueDefaultDescription,
            "issuetype": {
                "id": jiraTaskIssueTypeId
            },
            "components": [{
                "name": "BA"
            }],
            "customfield_10008": epicLink,
            "labels": [
                "welsh-qa"
            ]
        }
    });

    var requestOptions = {
        method: 'POST',
        headers: headers,
        body: jsonToCreateNewIssue
    };

    fetch(createIssueUrl, requestOptions)
        .then(response => {
            const jsonPromise = response.json()
                .then(data => {
                    const newIssue = data;
                    const newIssueKey = newIssue.key;
                    console.log(newIssueKey);

                    var jsonToAddLink = "";
                    jsonToAddLink = JSON.stringify({
                        "type": {
                            "name": "Relates",
                            "inward": "relates to",
                            "outward": "relates to"
                        },
                        "inwardIssue": {
                            "key": currentIssueKey
                        },
                        "outwardIssue": {
                            "key": newIssueKey
                        }
                    });

                    requestOptions = {
                        method: 'POST',
                        headers: headers,
                        body: jsonToAddLink
                    };

                    fetch(addLinkUrl, requestOptions)
                        .then(response => {
                            console.log(response.text())
                            const updateIssueUrl = `${jiraBaseUrl}/rest/api/latest/issue/${newIssueKey}/transitions`;

                            var jsonToUpdateStatus = "";
                            jsonToUpdateStatus = JSON.stringify({
                                "transition": {
                                    "id": "111",
                                    "name": "To Do"
                                }
                            });
        
                            requestOptions = {
                                method: 'POST',
                                headers: headers,
                                body: jsonToUpdateStatus
                            };

                            fetch(updateIssueUrl, requestOptions)
                            .then(response => {
                                console.log(response.text())
                                if(!debug) window.location.assign(currentUrl);
                            })
                            .catch(error => console.log('error', error))
        
                        })
                        .catch(error => console.log('error', error))
                });
        })
        .catch(error => console.log('error', error));

}

function myFunction(response) {
    console.log("myFunction. Logging response.text(): " + response.text())
}