The below script detects whether we are in Jira, and if it is run in Jira it will add a button. Clicking that button will use the REST API of Jira to create an issue, and navigate to the recently created issue.

// ==UserScript==
// @name         Tell Jira I did a thing
// @namespace    http://demuyt.net/
// @version      0.1
// @description  try to take over the world!
// @author       Tom J Demuyt
// @match        https://jira*
// @match        https://jira.it.aenetworks.com/*
// @grant        none
// ==/UserScript==


(function() {
    'use strict';

    let userName = "";
    let projectCode = "CF";
    let fixVersion = "15484";

    //The id of the create button is `create_link`, dont show up if that button is not there
    let createButton = document.getElementById('create_link');
    //Leave quietly if we cannot find that button

    //Get the parent (<ul>) of the <li> that holds the <a>
    let createButtonParent = createButton.parentNode.parentNode;

    //Add a button for the user
    var node = document.createElement("LI");
    node.innerHTML = '<li style="padding-left: 20px; text-decoration: underline; cursor: pointer;"><div id="idat">Log activity</div></li>';

    //Get a reference to the button
    let idat = document.getElementById("idat");

    //Make it listen to clicks;
    idat.addEventListener("click", recordTheThing);
    //Try and build a ticket
    function recordTheThing(){
        //Prep a call to Jira
        let xhr = new XMLHttpRequest(),
            url = '/rest/api/2/issue/';
        //Ask what the user did
        var thing = window.prompt("Describe the activity performed?","");
        //Get out if the user got cold feet
        //Start prepping the http request
        xhr.open('POST', url, true);
        //Use JSON since we will not fill in a form
        xhr.setRequestHeader("Content-Type", "application/json");
        //Prep the navigation to the new issue
        xhr.onreadystatechange = function () {
            //response: {"id":"125529","key":"CF-10282","self":"https://jira.it.aenetworks.com/rest/api/2/issue/125529"}
            //HTTP/REST return code 201 means created
            if (xhr.readyState === 4 && xhr.status === 201) {
                var json = JSON.parse(xhr.responseText);
                window.location.href = 'https://jira.it.aenetworks.com/browse/' + json.key;
        //The heart of the thing
        var data = JSON.stringify({
            "fields": {
                    "key": projectCode
                "summary": thing,
                "description": thing,
                "issuetype": {
                   "name": "Task"
                "assignee": {
                   "name": userName
                //15484 -> Busines As Usual
                "fixVersions": [{ "id": fixVersion}],
        //Finalize the REST call

    }//Record the thing

    //Find from the load/start the user id
    let xhr = new XMLHttpRequest(),
    url = '/rest/api/2/mypermissions/';
    //Prep to extract the username from the call header
    //200 -> OK
    xhr.onreadystatechange = function () {
      if(xhr.readyState == 4 && xhr.status == 200){
        userName = xhr.getResponseHeader("X-AUSERNAME");
    //Shoot and pray
    xhr.open('GET', url, true);

Please review for cleanliness, readability, standards, the usual..

  • \$\begingroup\$ To begin with... you're separating your let statements with comments, even though comments don't break anything. \$\endgroup\$ Oct 2 '18 at 13:26

The code is well commented. The indentation in most places seems to be four spaces but the last few lines have indentation of two spaces so that could be made more consistent. The last comment is a bit humorous...

It seems that if the button isn't found by the id attribute, it just bails. There could be alternative ways to find that button. For example, my company recently upgraded to version 7.11.2 and it appears that the create button still has an id attribute of create_link but the list item above it also has an id attribute of create-menu so that element could be found instead. And the unordered list also has a class name of aui-nav so if the create button can't be found the list could be found instead. I also see in the latest online version 1001.0.0 (e.g. *.atlassian.net) that the navigation menu has been moved to the left side of the screen and no longer uses list items so if your Jira gets updated you'll need to update your approach to finding that element.

I know you are familiar with const given your answers like this one so why not use it for things like projectCode, idat?

Also, a list item element is created and then the innerHTML contains another list item element:

var node = document.createElement("LI");
node.innerHTML = '<li style="padding-left: 20px; text-decoration: underline; cursor: pointer;"><div id="idat">Log activity</div></li>';

This yields HTML like below:

<li><li style="padding-left: 20px; text-decoration: underline; cursor: pointer;"><div id="idat">Log activity</div></li></li>  

MDN's documentation for <li> claims "It must be contained in a parent element: an ordered list (<ol>), an unordered list (<ul>), or a menu (<menu>)"1 and that the permitted content is Flow Content, which does not include list item elements. But obviously our browsers render it as expected. Ideally that list item would not contain a child list item...

You could consider using the fetch API instead of classical XHR requests unless browser compatibilty is an issue.

And since you are using ecmascript-2015 features like let, you could consider using more arrow functions...


  • \$\begingroup\$ Good call on const, very good call on the list item, will read about fetch. I am horrified by the abuse of anonymous fat arrow functions. \$\endgroup\$
    – konijn
    Oct 3 '18 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.