Documentation

Tutorial: My Requests in JIRA Service Desk

A pre-made repository containing all the code from this tutorial is available here.

This tutorial will show you how to build a static Atlassian Connect add-on that displays the list of Service Desk requests made by the currently logged-in user, on a page accessible from the agent portal.

As part of the tutorial, you'll learn about:

Using Node.js and the Atlassian Connect Express (ACE) toolkit, you will build an add-on that will interface with JIRA Service Desk via the new Service Desk REST API, and will make use of the AUI library for front-end styling.

The finished result will look similar to this:

Setting up your development environment

In this section, you'll install Node.js, and the Atlassian Connect Express (ACE) toolkit. Next, you'll use ACE to generate a new Atlassian Connect add-on project that includes a small "Hello, world!" example page. Finally, you'll deploy the generated add-on to a running cloud development instance of JIRA Service Desk.

Installing the toolchain

  1. Install Node.js 4.5.0 or later.

    If you use Homebrew, use the following command (you might need to enter sudo):

    $ brew install node
    

    If you use Windows or don't use Homebrew, just download and install Node.js directly.

  2. Install ACE using the following npm install command:
    $ npm install -g atlas-connect
    
    The ACE toolkit helps you create Connect add-ons using Node.js. ACE handles JSON web tokens (JWT), so that requests between your add-on and the JIRA application are signed and authenticated.

Creating the add-on project

  1. Use ACE to create a new Node.js project called sd-my-requests:
    $ atlas-connect new -t jira sd-my-requests
    
  2. Change to your new sd-my-requests directory:
    $ cd sd-my-requests
    
  3. Install the Node.js dependencies for your sd-my-requests project:
    $ npm install
    

The generated project contains a simple example "Hello, world!" page, which when deployed will be accessible from a button on JIRA's main navigation bar.

Feel free to open the atlassian-connect.json descriptor file and edit the name, description, and vendor properties. Don't change anything else at this stage.

Get a development version of JIRA Service Desk

Follow the guide in Development Setup to get a development version of JIRA and JIRA Service Desk.

Since we are developing with a local add-on against a cloud product, we will need to setup our environment to make our add-on accessible. You can do this by following our guide, Developing locally.

You'll also need to create a test Service Desk project along with some sample requests:

  1. Create a new Service Desk project via the "Projects" dropdown on the main navigation bar
  2. From within your new Service Desk project, click the "Customer channels" item on the sidebar, then "Visit the portal"
  3. Finally, from within the Customer Portal, create a few sample requests that we'll later use to test our finished product!

Getting things running

It's time to see your add-on in action! In this section, you'll deploy your add-on to your cloud instance of JIRA Service Desk. You'll also extend the JIRA Service Desk UI by making use of a plugin point inside the agent portal, and call the JIRA Service Desk REST API to retrieve your list of requests from the instance.

Deploying the add-on

Deploy your add-on by using this simple command from the sd-my-requests directory:

$ npm start

Since you are using ACE, this will start a local HTTP server to host your add-on.

To install the add-on, you will need to go to the Manage add-ons page in JIRA, click the Upload add-on and paste the ngrok link to your add-on.

Your add-on has now been deployed! Check it out by visiting your JIRA Service Desk. You will see a "Hello World" button in the main JIRA navigation bar, which will take you to the "Hello, world!" example page!

Extending the JIRA Service Desk UI

Atlassian Connect add-ons can be used to extend the UI of Atlassian products, via various plugin points that are built into various pages across the applications. The atlassian-connect.json descriptor is used to define Web UI modules, which can be attached to plugin points to inject additional content into pages (or add entirely new pages). Documentation on plugin point locations is available for JIRA here. Additionally, see Common Modules and JIRA Modules for more information on Web UI modules.

Let's try it out. In this section, you'll extend the JIRA Service Desk UI by adding a new page that displays all the requests made by the currently logged-in user:

  1. Go to the /views subdirectory, in your sd-my-requests directory.
  2. Create a file named my-requests.hbs and add the following content using an editor:

     {{!< layout}}
    
     <section class="aui-page-panel-item">
         <div class="aui-group">
             <div id="main-content" class="aui-item"></div>
         </div>
     </section>
    

    This file will serve as the template for your "My Requests" page.

  3. Go to the /routes subdirectory, in your sd-my-requests directory.
  4. Edit the index.js file and add the following route handling code, after the /hello-world route:
    app.get('/my-requests', addon.authenticate(), function (req, res) {
        res.render('my-requests');
    });
    
  5. Check that the file now looks like the following:

    module.exports = function (app, addon) {
    
        // Root route. This route will serve the `atlassian-connect.json` unless the
        // documentation url inside `atlassian-connect.json` is set
        app.get('/', function (req, res) {
            res.format({
                // If the request content-type is text-html, it will decide which to serve up
                'text/html': function () {
                    res.redirect('/atlassian-connect.json');
                },
                // This logic is here to make sure that the `atlassian-connect.json` is always
                // served up when requested by the host
                'application/json': function () {
                    res.redirect('/atlassian-connect.json');
                }
            });
        });
    
        // This is an example route that's used by the default "generalPage" module.
        // Verify that the incoming request is authenticated with Atlassian Connect
        app.get('/hello-world', addon.authenticate(), function (req, res) {
                // Rendering a template is easy; the `render()` method takes two params: name of template
                // and a json object to pass the context in
                res.render('hello-world', {
                    title: 'Atlassian Connect'
                    //issueId: req.query['issueId']
                });
            }
        );
    
        // Add any additional route handlers you need for views or REST resources here...
        // My Requests page
        app.get('/my-requests', addon.authenticate(), function (req, res) {
            res.render('my-requests');
        });
    
        // load any additional files you have in routes and apply those to the app
        {
            var fs = require('fs');
            var path = require('path');
            var files = fs.readdirSync("routes");
            for(var index in files) {
                var file = files[index];
                if (file === "index.js") continue;
                // skip non-javascript files
                if (path.extname(file) != ".js") continue;
    
                var routes = require("./" + path.basename(file));
    
                if (typeof routes === "function") {
                    routes(app, addon);
                }
            }
        }
    };
    

    You now have a page!

  6. Open your atlassian-connect.json descriptor and remove everything inside the modules object.
  7. Add a jiraProjectTabPanels section inside the modules object:
    "jiraProjectTabPanels": [
        {
            "key": "my-requests-link",
            "name": {
                "value": "My Requests"
            },
            "url": "/my-requests",
            "conditions": [
                {
                    "condition": "user_is_logged_in"
                },
                {
                    "condition": "can_use_application",
                    "params": {
                        "applicationKey": "jira-servicedesk"
                    }
                }
            ]
        }
    ]
    
  8. Verify that the file now looks like the following:
    {
        "key": "sd-my-requests",
        "name": "My Requests",
        "description": "My very first add-on",
        "vendor": {
            "name": "Angry Nerds",
            "url": "https://www.atlassian.com/angrynerds"
        },
        "baseUrl": "{{localBaseUrl}}",
        "links": {
            "self": "{{localBaseUrl}}/atlassian-connect.json",
            "homepage": "{{localBaseUrl}}/atlassian-connect.json"
        },
        "authentication": {
            "type": "jwt"
        },
        "lifecycle": {
            // atlassian-connect-express expects this route to be configured to manage the installation handshake
            "installed": "/installed"
        },
        "scopes": [
            "READ"
        ],
        "modules": {
            "jiraProjectTabPanels": [
                {
                    "key": "my-requests-link",
                    "name": {
                        "value": "My Requests"
                    },
                    "url": "/my-requests",
                    "conditions": [
                        {
                            "condition": "user_is_logged_in"
                        },
                        {
                            "condition": "can_use_application",
                            "params": {
                                "applicationKey": "jira-servicedesk"
                            }
                        }
                    ]
                }
            ]
        }
    }
    
  9. Restart your Atlassian Connect add-on.
  10. Reinstall the Connect add-on on your JIRA Service Desk.

You have now extended the JIRA Service Desk UI with your add-on! Check it out by going to the agent portal of your previously created Service Desk project. You will see a "My Requests" button under the "Add-ons" tab in the JIRA sidebar, which will take you to the "My Requests" page!

Using the JIRA Service Desk REST API

The JIRA Service Desk REST API is how Atlassian Connect add-ons communicate with JIRA Service Desk, either for retrieving data or sending it. For more information, see the JIRA Service Desk REST API reference (Cloud) and JIRA Service Desk REST API scopes.

For the purposes of this tutorial, you'll only be using a single REST endpoint: /rest/servicedeskapi/request. This endpoint is used to retrieve the list of requests made by the currently logged-in user.

The steps below will show you how to call the JIRA Service Desk REST API to retrieve the list of requests, then create and populate a table with the results:

  1. Go to the /public/js subdirectory, in your sd-my-requests directory.
  2. Edit the addon.js file, and add the following code:

    $(document).ready(function () {
        // Require the request module
        AP.require(['request', 'messages'], function(request, messages) {
            // GET our Service Desk requests via the JIRA Service Desk REST API
            request({
                url: '/rest/servicedeskapi/request',
                success: function (response) {
                    // Parse the response JSON
                    var json = JSON.parse(response);
    
                    // Store the base URL for later
                    var baseUrl = json._links.base;
    
                    // Did we get any requests back?
                    if (json.values.length > 0) {
                        // Create a table with the resulting requests
                        $('<table>').addClass('aui').append(
                            $('<thead>').append(
                                $('<tr>').append(
                                    $('<th>').text('Issue Key'),
                                    $('<th>').text('Current Status'),
                                    $('<th>').text('Summary'),
                                    $('<th>').text('Date Created'),
                                    $('<th>')
                                )
                            ),
                            $('<tbody>').append(
                                $.map(json.values, function (e) {
                                    // Map each request to a HTML table row
                                    return $('<tr>').append(
                                        $('<td>').append(
                                            $('<a>').attr('href',
                                                          baseUrl + '/browse/' + e.issueKey)
                                                    .attr('target', '_top')
                                                    .text(e.issueKey)
                                        ),
                                        $('<td>').text(e.currentStatus.status),
                                        $('<td>').text(e.requestFieldValues[0].value),
                                        $('<td>').text(e.createdDate.friendly),
                                        $('<td>').append(
                                            $('<a>').attr('href',
                                                          baseUrl + '/servicedesk/customer/portal/' + e.serviceDeskId + '/' + e.issueKey)
                                                    .attr('target', '_blank')
                                                    .text('View in customer portal')
                                        )
                                    );
                                })
                            )
                        ).appendTo('#main-content');
                    } else {
                        // Show a link to the Customer Portal
                        $('<div>').addClass('aui-message').append(
                            $('<p>').addClass('title').append(
                                $('<span>').addClass('aui-icon').addClass('icon-info'),
                                $('<strong>').text("It looks like you don't have any requests!")
                            ),
                            $('<p>').append(
                                $('<span>').text("Visit the "),
                                $('<a>').attr('href',
                                              baseUrl + '/servicedesk/customer/portals')
                                        .attr('target', '_blank')
                                        .text('Customer Portal'),
                                $('<span>').text(" to create some.")
                            )
                        ).appendTo('#main-content');
                    }
                },
                error: function (err) {
                    $('<div>').addClass('aui-message').addClass('aui-message-error').append(
                        $('<p>').addClass('title').append(
                            $('<span>').addClass('aui-icon').addClass('icon-error'),
                            $('<strong>').text('An error occurred!')
                        ),
                        $('<p>').text(err.status + ' ' + err.statusText)
                    ).appendTo('#main-content');
                }
            });
        });
    });
    
  3. Restart your Atlassian Connect add-on.

Your add-on can now make requests to the JIRA Service Desk REST API! Check it by going to your "My Requests" page. You will see a table populated with all your requests!

The finished result

Congratulations! You've successfully built your first Atlassian Connect add-on for JIRA Service Desk!

You should now have a basic understanding of the following:

  • how to create an Atlassian Connect add-on in Node.js with ACE
  • how to extend the JIRA Service Desk UI via plugin points specified in the atlassian-connect.json descriptor file
  • how to retrieve data via the JIRA Service Desk REST API

Additional resources