floodmeadows / Jira no fix version in ready for release

// ==UserScript==
// @name         Jira no fix version in ready for release
// @namespace    https://openuserjs.org/users/floodmeadows
// @description  Show list of Jira tickets with a state of Ready for Release without a value for fix_version
// @copyright    2022, floodmeadows (https://openuserjs.org/users/floodmeadows)
// @license      MIT
// @version      0.4
// @include      https://jira.*.uk/secure/RapidBoard.jspa?rapidView=5483*
// @grant        none
// @updateURL    https://openuserjs.org/meta/floodmeadows/Jira_no_fix_version_in_ready_for_release.meta.js
// @downloadURL  https://openuserjs.org/install/floodmeadows/Jira_no_fix_version_in_ready_for_release.user.js
// ==/UserScript==

// ==OpenUserJS==
// @authors       floodmeadows
// ==/OpenUserJS==
/* jshint esversion: 6 */

//--- Enter your search query -----------//
const jql = 'MY_JIRA_SEARCH_QUERY'; // e.g. 'project = MY-PROJECT AND status in (LIST_OF_STATUS_VALUES) ORDER BY key'
//---------------------------------------//

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

(function () {
    'use strict';

    addPossibleIssuesContainer();
    checkForProblemIssues();
})();

function addPossibleIssuesContainer() {
    const parentElementId = 'ghx-modes-tools';
    var subtasksToCheckContainer = document.createElement("div");
    var t = "Possible issues: ";
    subtasksToCheckContainer.setAttribute('id','subtasks-to-check-container');
    subtasksToCheckContainer.setAttribute('style','position:absolute; top:4em; right:1.5em; margin-top:0.5em; text-align:right;');

    document.getElementById(parentElementId).appendChild(subtasksToCheckContainer);
}

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

    const baseApiUrl = myJiraBaseUrl + '/rest/api/latest/search';
    const baseStoryUrl = myJiraBaseUrl + '/browse/';
    const fields = 'key,summary,status';
    const jiraApiSearchUrl = baseApiUrl + '?jql=' + encodeURI(jql) + '&fields=' + fields;
    const jiraWebSearchUrl = myJiraBaseUrl + '/issues/?jql=' + encodeURI(jql);
    console.log('api URL: ' + jiraApiSearchUrl);
    console.log('web URL: ' + jiraWebSearchUrl);

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

    fetch(jiraApiSearchUrl, requestOptions)
        .then(response => response.json())
        .then(
            json => {
                var problemIssues = [];
                // console.log('json = ' + JSON.stringify(json))
                for (const [_, issue] of Object.entries(json.issues)) {
                    console.log("issue.fields.fixVersions = " + issue.fields.fixVersions);
                    if (issue.fields.status.name == "Ready for Release" && typeof(issue.fields.fixVersions == 'undefined')) {
                        problemIssues.push(" <a href='" + baseStoryUrl + issue.key + "' target='_blank' title='" + issue.fields.summary.replace(/'/g, "&apos;") + "'>" + issue.key + "</a>");
                        console.log(baseStoryUrl + issue.key + " is in Ready for Release, but has no fixVersion.");
                    }
                }
                var e = document.getElementById('subtasks-to-check-container');
                if (problemIssues.length > 0) {
                    console.log("R4R but no fix version: " + problemIssues);
                    e.innerHTML = '<a href="' + jiraWebSearchUrl + '" target="_blank">' + problemIssues.length + ' items</a> Ready for Release but no fix version: ' + problemIssues;
                } else {
                    e.innerHTML = "All good: Ready for Release tickets all have fixVersions.";
                }
            }
        )
        .catch(error => console.log('error', error));
}