floodmeadows / Jira append description from template story

// ==UserScript==
// @name         Jira append description from template story
// @namespace    https://openuserjs.org/users/floodmeadows
// @description  Adds button to copy description from template story and append to current story description
// @copyright    2023, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license      MIT
// @version      0.2
// @include      https://jira.*.uk/browse/*
// @updateURL    https://openuserjs.org/meta/floodmeadows/Jira_append_description_from_template_story.meta.js
// @downloadURL  https://openuserjs.org/install/floodmeadows/Jira_append_description_from_template_story.user.js
// @grant        none
// ==/UserScript==

/* jshint esversion: 6 */

//--- Customise your template stories here ----//
const radioButtonPageTemplateIssueKey = 'APB-10130';
const textFieldPageTemplateIssueKey = 'APB-10131';
//-------------------------------------//

const currentUrl = new URL(document.URL);
const jiraBaseUrl = currentUrl.protocol + '//' + currentUrl.host;

const debug = false;
const targetElementForButtonsAndLinks = document.getElementById('descriptionmodule-label');

(function () {
    'use strict';

    if (debug) addButton("Clear description", targetElementForButtonsAndLinks, clearDescription);

    addLink("Radio button template", targetElementForButtonsAndLinks, jiraBaseUrl + "/browse/" + radioButtonPageTemplateIssueKey);
    addButton("Append radio button template", targetElementForButtonsAndLinks, appendRadioButtonTemplateTextToCurrentDescription);

    addLink("Text field template", targetElementForButtonsAndLinks, jiraBaseUrl + "/browse/" + textFieldPageTemplateIssueKey);
    addButton("Append text field template", targetElementForButtonsAndLinks, appendTextFieldTemplateTextToCurrentDescription);
})();

function addButton(buttonText, targetElement, functionName) {
    const button = document.createElement("button");
    button.setAttribute("class", "aui-button");
    button.addEventListener("click", functionName);
    const text = document.createTextNode(buttonText);
    button.appendChild(text);
    targetElement.after(button);
}

function addLink(linkText, targetElement, url) {
    const link = document.createElement("a");
    link.setAttribute("href", url);
    link.setAttribute("style", "margin-left: 8px;");
    const text = document.createTextNode(linkText);
    link.appendChild(text);
    targetElement.after(link);
}


function appendRadioButtonTemplateTextToCurrentDescription() {
    appendTemplateTextToCurrentDescription(radioButtonPageTemplateIssueKey);
}

function appendTextFieldTemplateTextToCurrentDescription() {
    appendTemplateTextToCurrentDescription(textFieldPageTemplateIssueKey);
}


function appendTemplateTextToCurrentDescription(templateIssueKey) {
    //--- Get standard info ---//
    const currentIssueKey = document.getElementById("key-val").childNodes[0].nodeValue;
    const currentIssueApiUrl = `${jiraBaseUrl}/rest/api/latest/issue/${currentIssueKey}`;
    const templateIssueApiUrl = `${jiraBaseUrl}/rest/api/latest/issue/${templateIssueKey}`;

    if(debug) console.log('URL: ' + currentIssueApiUrl);

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

    var requestOptions = {
        method: 'GET',
        headers: headers
    };

    /* --- start block for fetching the template issue details --- */
    fetch(templateIssueApiUrl, requestOptions)
        .then(response => {
            const jsonPromise = response.json()
                .then(data => {
                    const templateIssue = data;
                    if (debug) console.log(templateIssue);
                    console.log("Template description = '" + templateIssue.fields.description + ".'");
                    const templateDescription = templateIssue.fields.description;
                    /* --- start block for fetching the current issue details --- */
                    fetch(currentIssueApiUrl, requestOptions)
                        .then(response => {
                        const jsonPromise = response.json()
                        .then(data => {
                            const currentIssue = data;
                            if (debug) console.log(currentIssue);
                            console.log("Current description = '" + currentIssue.fields.description + ".'");
                            const currentDescription = currentIssue.fields.description;
                            var newDescription = "";
                            if (currentDescription != null) {
                                newDescription = currentDescription + "\r\n\r\n" + templateDescription;
                            } else {
                                newDescription = templateDescription;
                            }
                            console.log("New description = '" + newDescription + ".'");
                            updateDescription(newDescription);

                        });
                    })
                        .catch(error => {
                        console.log('Error fetching current issue: ', error);
                        return false;
                    });
                    /* --- end block for fetching the current issue details --- */
                });
            })
        .catch(error => {
            console.log('Error fetching template issue: ', error);
            return false;
        });
        /* --- end block for fetching the template issue details --- */
}

function clearDescription() {
    updateDescription("");
}

function updateDescription(newDescription) {
    //--- Get standard info ---//
    const currentUrl = new URL(document.URL);
    const jiraBaseUrl = currentUrl.protocol + '//' + currentUrl.host;
    const currentIssueKey = document.getElementById("key-val").childNodes[0].nodeValue;
    const updateIssueUrl = `${jiraBaseUrl}/rest/api/latest/issue/${currentIssueKey}`;

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

    var jsonToUpdateIssue = JSON.stringify({
        "fields": {
            "description": newDescription
        }
    });

    if (debug) console.log(jsonToUpdateIssue);

    var requestOptions = {
        method: 'PUT',
        headers: headers,
        body: jsonToUpdateIssue
    };

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