Sidebar JavaScript API for JIRA project-centric view

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. 

Accessing the sidebar

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:

On this page:

JIRA.API.getSidebar().done(function(Sidebar)) {
	// Using local reference
	Sidebar.getGroup('workflow');
 
    // Using global reference
	JIRA.API.Sidebar.getGroup('workflow');
})

Selecting elements

Navigation groups

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.

<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>
// 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" 

Navigation items

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.

<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>
// 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"

Navigation subgroups

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.

<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>
// 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" 

Reacting to user actions

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).

before:select

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.

// 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 :(');
});

select

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.

before:navigate

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.

// 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.

// 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();
});

 

Example workflow — changing selection

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:

  1. Trigger before:select on B. If prevented, stop now
  2. Trigger before:deselect on A. If prevented, stop now.
  3. Deselect item A.
  4. Trigger deselect on A.
  5. Select item B
  6. Trigger select on B.
  7. Trigger before:navigate on B. If prevented, stop now.
  8. Go to B link.

Simulating user actions

The API provides two methods for simulating the user's actions, select() and navigate():

select()

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.

switch(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:

  • Initial load of the plugin
  • Changing the plugin page using keyboard shortcuts
  • Changing the page using internal links in the plugin

navigate()

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:

// For example, use keyboard shortcuts to go to an item
AJS.whenIType('1').execute(function(){
	JIRA.API.Sidebar.getItem('plan').navigate();
});

Listening to multiple items

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.

 

// 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',...) 

Need help?

Try the following resources:

Was this page helpful?

Have a question about this article?

See questions about this article

Powered by Confluence and Scroll Viewport