This document will show you how to develop for the new JIRA sidebar using the JavaScript API.
The sidebar is the main feature of the new project-centric view in JIRA. Read the Design guide - JIRA project-centric view, then the Development guide - JIRA project-centric view before you read this page.
The Sidebar API is a singleton exposed under the global variable JIRA.API.Sidebar
. Please, note that this global variable loads asynchronously.
If you need to know when the Sidebar is ready to be used, use JIRA.API.getSidebar()
. This method will return a promise, that will eventually be resolved when the Sidebar is ready. For example:
1 2JIRA.API.getSidebar().done(function(Sidebar)) { // Using local reference Sidebar.getGroup('workflow'); // Using global reference JIRA.API.Sidebar.getGroup('workflow'); })
The Sidebar is a collection of NavigationGroup. A NavigationGroup is defined by an HTML element with the class aui-sidebar-group
. Each NavigationGroup can have an optional id, defined by the attribute data-id
(the main group has id "default"). If a group is not found, the get method will return undefined
. If there are two groups with the same ID, the Sidebar will log a warning in the JavaScript console. When a group is selected, you can use group.id
to retrieve the ID of the group.
1 2<div class="aui-navgroup-inner"> <div class="aui-sidebar-group" data-id="sidebar-navigation-panel">...</div> <div class="aui-sidebar-group" data-id="workflow">...</div> <div class="aui-sidebar-group">...</div> </div>
1 2// Get group by ID: JIRA.API.Sidebar.getGroup('workflow'); // Get group by index: JIRA.API.Sidebar.getGroupAt(1); // Get the default group, these methods are equivalent: JIRA.API.Sidebar.getDefaultGroup(); JIRA.API.Sidebar.getGroup('sidebar-navigation-panel'); JIRA.API.Sidebar.getGroupAt(0); // Get the ID of the group console.log(JIRA.API.Sidebar.getGroupAt(1).id) //"workflow"
Each group is a collection of NavigationItems. A navigation item is defined by a list item (<LI>
inside a <UL>
) that contains an <A>
tag. The navigation item can contain an optional id, defined by the attribute data-link.id
. If there are two items with the same id, the Sidebar will log a warning in the console. If the user calls getItem()/getItemAt()
directly in the Sidebar, it will search for the item in the default group. Similar to getGroup()
/getGroupAt()
, if the item does not exist, it will return undefined
. When an item is selected, you can use item.id
to retrieve the ID of the item.
1 2<div class="aui-sidebar-group" data-id="sidebar-navigation-panel"> <ul> <li><a href="/plan" data-link-id="plan">Plan</a></li> <li><a href="/work" data-link-id="work">Work</a></li> <li><a href="/report">Report</a></li> </ul> </div>
1 2// Get group by ID, two ways of getting the 'plan' item. JIRA.API.Sidebar.getDefaultGroup().getItem('plan'); JIRA.API.Sidebar.getItem('plan'); // Get group by index, two ways of getting the 'report' item. JIRA.API.Sidebar.getDefaultGroup().getItemAt(2); JIRA.API.Sidebar.getItemAt(2); // Get the ID of the item console.log(JIRA.API.Sidebar.getItemAt(1).id) //"work"
A Navigation subgroup is a nested group inside a NavigationSubgroup. It is defined by a nested <UL>/<LI>
list inside a Navigation Item. In order to select it, the user can use getItem()/getItemAt().
A NavigationSubgroup behaves like a NavigationGroup, the user can use getItem()/getItemAt()
to select items inside the NavigationSubgroup. As usual, if the NavigationSubgroup does not exist, it will return undefined
. When an subgroup is selected, you can use subgroup.id
to retrieve the ID of the subgroup.
1 2<div class="aui-sidebar-group" data-id="sidebar-navigation-panel"> <ul> <li> <a href="#" data-link-id="releases">Releases</a> <ul> <li><a href="#">Release #1</a></li> <li><a href="#">Release #2</a></li> <li><a href="#" data-link-id="all">All</a></li> </li> </ul> </div>
1 2// Get the navigation subgroup. JIRA.API.Sidebar.getItem('releases'); JIRA.API.Sidebar.getItemAt(0); // Get the items inside the navigation subgroup. JIRA.API.Sidebar.getItem('releases').getItemAt(0); JIRA.API.Sidebar.getItem('releases').getItem('all'); // Get the ID of the subgroup console.log(JIRA.API.Sidebar.getItemAt(0).id) //"releases"
When a user clicks a NavigationItem, the sidebar will throw events to programmatically react to the click action. By default, it will follow the link specified in the href
attribute. These three events are triggered in order:
before:select
select
before:navigate
Note, these events are not triggered for links that open in a new tab (i.e. with target="_blank"
or clicked with ctrl
/cmd
key).
This event means that the Sidebar is about to mark an element as selected. This event can be prevented, meaning that the Sidebar will not highlight the element, and will not navigate to the link. Also, if there is an already selected item, it will not be deselected.
1 2// When the user clicks on the Releases > All link... JIRA.API.Sidebar.getItem('releases').getItem('all').on('before:select', function(event) { // Avoid item to be selected. event.preventDefault(); // Notify the user. alert('All releases functionality is not ready yet :('); });
This is similar to the before:select
event, however it means that the Sidebar has marked an element as selected (i.e. it happens after before:select
). This event is not preventable.
This event means that the Sidebar (more specifically: the browser) is about to navigate to the URL specified in the item. This event is preventable. If it is not prevented, the browser will load a different page. Use this event if you want to avoid a page loading, but you still want the item to be marked as selected.
1 2// When the user clicks on the Releases > All link... JIRA.API.Sidebar.getItem('releases').getItem('all').on('before:navigate', function(event) { // Stop navigation event.preventDefault(); // Load the releases JAG.ReleaseManager.render('all'); });
When the user clicks a link, the Sidebar deselects the currently selected link (if any). This action also triggers two events:
before:deselect
deselect
These events are similar to the before:select
and select
events. For example, the user can prevent before:deselect
to stop the item from being deselected (and the new item from being selected), and ask the user for confirmation before leaving.
1 2// For example, use keyboard shortcuts to select an item JIRA.API.Sidebar.getItem('releases').getItem('all').on('before:deselect', function(event) { var wantToLeave = confirm("Are you sure you want to leave this awesome page?"); if (!wantToLeave) event.preventDefault(); });
This section shows how the events described above would be triggered in a typical user workflow. In this case, the scenario is changing a selection.
Say there are two items: item A and item B, where item A is selected and item B is not selected initially. If a user selects item B, the flow of the actions would look like this:
before:select
on B. If prevented, stop nowbefore:deselect
on A. If prevented, stop now.deselect
on A.select
on B.before:navigate
on B. If prevented, stop now.The API provides two methods for simulating the user's actions, select()
and navigate()
:
This method will highlight the selected item, but it will not perform any navigation. It will trigger the before:select
and select
events. This should be used when the plugin has changed the page and you want to inform the user about the new page.
1 2switch(GH.RapidBoard.ViewController.getMode()) { case 'plan': JIRA.API.Sidebar.getGroup('sidebar-workflow-panel').getItem('com.pyxis.greenhopper.jira:project-sidebar-plan').select(); break; case 'work': JIRA.API.Sidebar.getGroup('sidebar-workflow-panel').getItem('com.pyxis.greenhopper.jira:project-sidebar-work').select(); break; case 'report': JIRA.API.Sidebar.getGroup('sidebar-workflow-panel').getItem('com.atlassian.jira.jira-projects-plugin:report-page').select(); break; }
You may want to use this method in the following scenarios:
This method will follow the link specified in the HREF
. It will trigger the preventable event before:navigate
. Plugins can use this method to restart themselves, as a call to navigate()
will trigger a new page load. For example:
1 2// For example, use keyboard shortcuts to go to an item AJS.whenIType('1').execute(function(){ JIRA.API.Sidebar.getItem('plan').navigate(); });
Listening for events in each individual item is useful, but it can be cumbersome in some use cases. For example, if you have a NavigationSubgroup that shows all of the releases for a project, you probably want to handle a click in any of the individual releases in the same way. Adding an event to each release would be too verbose.
To help with this case, all the events (before:select, select, ``before:navigate, ``before:deselect and deselect
) will "bubble up" from the Item all the way up to the Sidebar component, including any group or subgroup. The user can listen for the events in any of the groups, and use event.emitter
to access to the actual item that triggered the event.
1 2// When 'Releases > All' is selected, all these handlers will be triggered: // JIRA.API.Sidebar.getGroup('workflow').getItem('releases').getItem('all').on(<event>, <handler>); // JIRA.API.Sidebar.getGroup('workflow').getItem('releases').on(<event>, <handler>); // JIRA.API.Sidebar.getGroup('workflow').on(<event>, <handler>); // JIRA.API.Sidebar.on(<event>, <handler>); // Example JIRA.API.Sidebar.getGroup('workflow').on('before:navigate', function(event) { event.preventDefault(); // Which element was selected? switch (event.emitter.id) { case "plan": JAG.PlanView.render(); break; case "workflow": JAG.WorkflowView.render(); break; case "report": JAG.ReportsView.render(); break; } });
About the order of the events
The order in which a bubbled event is fired is not reliable: some events fire the event on the item first then on the parent groups, while other events do the opposite. This order is buried deeply in the libraries that were used to implement the Sidebar, and it is not explicitly documented. This means that it can change without notice. Hence, you should not assume that JIRA.API.Sidebar.on('select',...)
will be executed after JIRA.API.Sidebar.getItem('release').on('select',...)
Try the following resources:
Rate this page: