Guide - Building a dashboard item for a JIRA P2 add-on

This guide will help you build a dashboard item for a JIRA P2 add-on. You will need to be familiar with building JIRA P2 add-ons to use this guide. If you are building a dashboard item for a JIRA Connect add-on, see this guide instead: Building a dashboard item for JIRA Connect add-on.

A dashboard item is similar to a gadget, in that it provides discrete dynamic content that a user can use to customize their dashboard. However, dashboard items use modern rendering technologies like AMD, Soy, LESS, etc. Dashboard items are also able to share web-resources, which greatly improves page load performance by reducing the number of requests and the overall size of data to be transferred on a dashboard load.

  The long term plan for dashboard items...

Dashboard items will eventually replace gadgets in JIRA. They are easy to build and are faster. Gadgets are rendered in iframes and cannot share web-resources, which makes them slow to load. Gadgets are also based on the OpenSocial specification, which is no longer championed by Google. 

Before you begin

  • If you are replacing a gadget with a dashboard item for your add-on,  do not modify the existing OpenSocial gadget code . This provides you with a fallback, in case something goes wrong with your dashboard item — you can simply turn off the add-on module for the dashboard item and the old OpenSocial gadget will render instead.
  • Unlike gadgets, dashboard items do not support remoting, e.g. embedding an OpenSocial gadget from JIRA on a Confluence page. We don't have plans to support remoting for dashboard items at this point in time.

Defining the dashboard item

The way that you define a dashboard item in your add-on description depends on whether you are building a new dashboard item or replacing an existing OpenSocial gadget:

  • Creating a new "standalone" dashboard item — You are building a completely new dashboard item.
  • Replacing a gadget with a dashboard item — You are replacing an existing gadget with a dashboard item. The OpenSocial gadget still needs to be defined in your add-on. A "replacement" dashboard item works exactly the same as a "standalone" gadget. The only differences are that the gadget directory is populated from the OpenSocial gadget definition and that what is persisted in the database is still an OpenSocial gadget. The dashboard item only becomes active when the dashboard is rendered.

Creating a new "standalone" dashboard item

This is the definition for a "standalone" dashboard item:

<dashboard-item key="login-dashboard-item">
    <definition>
        <title key="gadget.login.title"/>
        <categories>
            <category>JIRA</category>
        </categories>
        <author>
            <name>Atlassian</name>
        </author>
        <thumbnail location="/download/resources/com.atlassian.jira.gadgets:login-dashboard-item-resources/login-thumb.png"/>
    </definition>
    <description key="gadget.login.description"/>
    <resource name="view" type="soy" location=":login-dashboard-item-resources/JIRA.DashboardItem.Login.Templates.Login"/>
    <amd-module>jira-dashboard-items/login</amd-module>
    <context-provider class="com.atlassian.jira.dashboarditem.login.LoginContextProvider"/>
    <condition class="com.atlassian.jira.plugin.webfragment.conditions.IsAnonymousUserCondition"/>
</dashboard-item>

About the "standalone" dashboard-item definition:

<definition /> This information is used to populate the dashboard item's entry in the gadget directory. The gadget directory is where users select gadgets to add to the dashboard.
<resource name="view" .../>  The "view" resource is optional.
You can use this to render a dashboard item entirely server-side, by using an optional <context-provider /> to provide the data for rendering.
For example, this approach is used for the JIRA administration, introduction and login gadgets.
<amd-module /> The "amd-module" parameter is optional.
You can use this to specify a JavaScript AMD (Asynchronous Module Definition) module for your dashboard item. See example AMD module   below.
When the dashboard renders, it will call this module and provide it with the dashboard item's surrounding <div/> as context.
<condition /> The "condition" parameter is optional. You can use this to show or hide the dashboard item on a dashboard and/or in the gadget directory.

Replacing a gadget with a dashboard item

This is the definition for a dashboard item that replaces a gadget:

<dashboard-item key="login-dashboard-item">
     <replace-gadget-spec-uri>rest/gadgets/1.0/g/com.atlassian.jira.gadgets/gadgets/login.xml</replace-gadget-spec-uri>
     <resource name="view" type="soy" location=":login-dashboard-item-resources/JIRA.DashboardItem.Login.Templates.Login"/>
     <amd-module>jira-dashboard-item/login</amd-module>
     <context-provider class="com.atlassian.jira.dashboarditem.login.LoginContextProvider"/>
 </dashboard-item>

About the "replacement" dashboard-item definition:

<replace-gadget-spec-uri />

As described at the start of this section, the gadget that is being replaced by this dashboard item still needs to be defined in your add-on.
Specify the definition of the gadget in this element.

<resource name="view" .../>   The "view" resource is optional.
You can use this to render a dashboard item entirely server-side, by using an optional  <context-provider />  to provide the data for rendering.
For example, this approach is used for the JIRA administration, introduction and login gadgets.
<amd-module /> The "amd-module" parameter is optional.
You can use this to specify a JavaScript AMD (Asynchronous Module Definition) module for your dashboard item. See Example AMD module below.
When the dashboard renders, it will call this module and provide it with the dashboard item's surrounding <div/> as context.

General development guidelines

We recommend that you read all of the guidelines below before developing a dashboard item. These are high level guidelines, as this guide is intended for experienced add-on developers. If you need help with a specific development issue, try browsing the JIRA development forums.

In this section:

Setting the correct context

Unlike OpenSocial gadgets, dashboard items are not sandboxed in iframes. Hence, you need to set the correct context for the CSS/LESS and JavaScript of your dashboard item to ensure that it doesn't interfere with other dashboard items.

  • Ensure the CSS/LESS is properly namespaced — This ensures that the styling of your dashboard item does not interfere with other dashboard items on the dashboard.
  • Ensure all JavaScript operates in the context of the passed <div /> — All JavaScript must operate within the context of the passed <div /> when the dashboard item is initialized. This ensures that event handlers, for example, only get bound within the current dashboard item and don't affect other dashboard items.

Performance

  • Only use server-side rendering for mostly static information — Anything that might be expensive (e.g. running a JQL query, generating data for a chart, etc) should not be done server-side, otherwise it will delay the rendering of the entire dashboard. Instead, the data should be requested via an AJAX request and then rendered client-side.

Sharing resources

  • Using shared AMD modules and soy templates — You can introduce shared AMD modules and soy templates, where this makes sense for common configuration form elements (e.g. filter pickers)

Testing your dashboard item

  • Unit testing — We recommend testing all new code with a JavaScript unit testing framework, like QUnit.
  • Testing "replacement" dashboard items — We recommend that you test your "replacement" dashboard item by creating an instance of the old gadget and then enabling your new dashboard item. You can then check whether your dashboard item is compatible with the preferences of the old gadget.

Example AMD module

If you want to specify a JavaScript AMD (Asynchronous Module Definition) module for your dashboard item, you can use the example below as a guideline:

define("jira-dashboard-items/sample-dashboard-item", [
    'underscore'
], function (_) {
    var DashboardItem = function (API) {
        this.API = API;
    };
    /**
     * Called to render the view for a fully configured dashboard item.
     *
     * @param context The surrounding <div/> context that this items should render into.
     * @param preferences The user preferences saved for this dashboard item (e.g. filter id, number of results...)
     */
    DashboardItem.prototype.render = function (context, preferences) {
        //TODO: render the view with the preferences provided
        this.API.once("afterRender", _.bind(function () {
            this.API.showLoadingBar();
        }, this));
    };
    /**
     * Called to render the configuration form for this dashboard item if preferences.isConfigured
     * has not been set yet.
     *
     * @param context The surrounding <div/> context that this items should render into.
     * @param preferences The user preferences saved for this dashboard item 
     */
    DashboardItem.prototype.renderEdit = function (context, preferences) {
        //TODO: render a config form here using provided SOY templates and assign it
        //      to the 'form' variable
        form.on("submit", _.bind(function (e) {
            e.preventDefault();
            if (!validateFields()) {  //TODO: validateFields needs to implemented
                this.API.forceLayoutRefresh();
                return;
            }
            this.API.savePreferences({
                //provide parsed prefs from your config form here
                //to store them for this dashboard item
            });
        }, this));
        form.find("input.button.cancel").on("click", _.bind(function () {
            this.API.closeEdit();
        }, this));
    };
    return DashboardItem;
});

An API interface is passed to the AMD module in the example above. The table below describes this interface:

API interface:

Method Description
isEditable

Check if a dashboard item is configurable and if the current user has permission to edit this dashboard item's configuration.
Returns {boolean} true if the current user can edit the gadget.

getRefreshFieldValue

Helper to extract the correct value to be persisted for a refresh field rendered with .refreshInterval
Returns {string} value that should be persisted.

Parameters:

  • fieldName (string) — Refresh field name, defaults to "refresh".
savePreferences

Tries to save the passed preferences on the server for this dashboard item.

If the user doesn't have permission to edit this dashboard item, no action will be performed.

Parameters:

  • preferences (object) — The new preferences object to save for this dashboard item.
setTitle

Sets the title for the dashboard item.

Parameters:

  • title (string) — The new title for the dashboard item.
initRefresh
Trigger a refresh of the dashboard item.
showLoadingBar
Shows the loading bar for the dashboard item.
hideLoadingBar
Hides the loading bar for the dashboard item.
getContext
Returns the context for the dashboard item.
closeEdit
Close the edit dialog of the dashboard item.
getGadgetId
Returns the Id for the dashboard item.
resize

When you add some content dynamically to your dashboard item and it causes the height to increase a scroll will appear.

Call this method to resize the content automatically and make the scroll go away.

 

 

Design guidelines

There are no design guidelines specific to dashboard items. We recommend that you consult the Atlassian Design Guidelines, as you should when developing for any Atlassian product. Here are a few topics that may be relevant to your dashboard item:

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport