Level of experience: | Beginner. This is a good tutorial to try if you have never developed an app before. |
Time estimate: | It should take you approximately 1 hour to complete this tutorial. |
Applicable: | Jira 7.0.0 and later |
This tutorial shows you how to add content to the View Issue page in Jira. It demonstrates how to create an app that adds a web panel to the page if the issue has a due date. Web panel displays a colorful indication of when an issue is due (or overdue).
Completed app consists of the following components:
DueDateIndicator
class that calculates the due date for an issue and exposes it as an object context
that we can use in Jira UI templates.tutorial-jira-add-content-to-view-issue-screen.properties
file and a Velocity template
(that is, the due-date-indicator.vm
file) for rendering the web panel plugin module.When you are finished, all these components are packaged in a single JAR file.
About these instructions
You can use any supported combination of operating system and IDE to create this app. These instructions were written using IntelliJ IDEA 2017.2 on macOS Sierra. If you use another operating system or IDE combination, you should use the equivalent operations for your specific environment. This tutorial was last tested with Jira 7.7.1 using the Atlassian SDK 6.3.10.
To complete this tutorial, you need to know the following:
We encourage you to work through this tutorial. If you want to skip ahead or check your work when you have finished, you can find the app source code on Atlassian Bitbucket.
To clone the repository, run the following command:
1 2git clone https://bitbucket.org/atlassian_tutorial/jira-add-content-to-view-issue-screen
Alternatively, you can download the source as a ZIP archive.
In this step, you'll use two atlas-
commands to generate stub code for your app. The atlas-
commands are part of
the Atlassian Plugin SDK and automate much of the work of app development for you.
Set up the Atlassian Plugin SDK and Build a Project if you have not done it yet.
Open a Terminal on your machine and navigate to directory where you would like to keep your app code.
To create an app skeleton, run the following command:
1 2atlas-create-jira-plugin
To identify your app, enter the following information.
group-id |
|
artifact-id |
|
version |
|
package |
|
Confirm your entries when prompted.
Navigate to the tutorial-jira-add-content-to-view-issue-screen
directory created in the previous step.
Delete the test directories.
1 2rm -rf ./src/test/java rm -rf ./src/test/resources/
Delete the unneeded Java class files.
1 2rm -rf ./src/main/java/com/example/plugins/tutorial/*
Import the project into your favorite IDE.
It is a good idea to familiarize yourself with the project configuration file known as the POM
(that is, Project Object Model definition file).
In this section, you will review and tweak the pom.xml
file.
The POM is located at the root of your project and declares the project dependencies and other information.
In the root folder of your app, open the pom.xml
file.
In the organization
element, add your company or organization name and your website URL.
The following code block shows how it looks in plain text:
1 2<organization> <name>Example Company</name> <url>http://www.example.com/</url> </organization>
Update the description
element with the following:
1 2<description>This plugin shows the due date for an issue in a new panel on the View Issue page.</description>
Modify the name
element to be something more readable (optional):
1 2<name>Due Date Indicator on the 'View Issue' Page</name>
This is the name for your app that will appear on the Jira app administration page.
Save the file.
Your stub code contains an app descriptor file atlassian-plugin.xml
. This is an XML file that identifies the app to
the host application (Jira) and defines the required app functionality.
In your IDE, navigate to src/main/resources
and open the descriptor file.
You should see something like this (comments removed):
1 2<atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2"> <plugin-info> <description>${project.description}</description> <version>${project.version}</version> <vendor name="${project.organization.name}" url="${project.organization.url}" /> <param name="plugin-icon">images/pluginIcon.png</param> <param name="plugin-logo">images/pluginLogo.png</param> </plugin-info> <resource type="i18n" name="i18n" location="tutorial-jira-add-content-to-view-issue-screen"/> <web-resource key="tutorial-jira-add-content-to-view-issue-screen-resources" name="tutorial-jira-add-content-to-view-issue-screen Web Resources"> <dependency>com.atlassian.auiplugin:ajs</dependency> <resource type="download" name="tutorial-jira-add-content-to-view-issue-screen.css" location="/css/tutorial-jira-add-content-to-view-issue-screen.css"/> <resource type="download" name="tutorial-jira-add-content-to-view-issue-screen.js" location="/js/tutorial-jira-add-content-to-view-issue-screen.js"/> <resource type="download" name="images/" location="/images"/> <context>tutorial-jira-add-content-to-view-issue-screen</context> </web-resource> </atlassian-plugin>
Note that some of the information from the POM is transferred to the app descriptor using variable names such
as ${project.name}
.
Now you will use the plugin module generator (that is, another atlas-
command) to generate the stub code
for modules that the app needs.
For this step, you will need a web panel plugin module. You'll add this using
the atlas-create-jira-plugin-module
command. The command can also generate an i18n properties file for your
Jira UI text, which we'll add as well.
Open a Terminal, navigate to the app root folder where the pom.xml
is located, and then run the following command:
1 2atlas-create-jira-plugin-module
Select the Web Panel option, and then add the following information.
Enter Plugin Module Name |
|
Enter Location |
|
For more information, see Right Side of the 'View Issue' Page Location.
Select 'y' for the Show Advanced Setup prompt.
For the next five options, you can accept the default by selecting enter. For reference, the values are the following.
Module Key |
|
Module Description |
|
i18n Name Key |
|
i18n Description Key |
|
Weight |
|
Select 'y' for Add Resource prompt, and then enter the following information for the resource.
Enter Resource Name |
|
Enter Resource Type |
|
Enter Location (path to resource file) |
|
Select 'N' for Add Resource Parameter prompt.
Select 'N' for Add Resource.
Select 'y' for Add Velocity Context Provider.
For Add Fully Qualified Context Provider Class prompt enter the following: com.example.plugins.tutorial.DueDateIndicator
.
Select 'N' for Add Conditions.
Select 'N' for Add Another Plugin Module.
The SDK finishes generating your plugin module and returns you to the command prompt.
The SDK gives us most of what we need for the app configuration, but we'll need to add a title for our panel manually.
Navigate to src/main/resources
and open the atlassian-plugin.xml
file.
Add the following label
element as a child of web-panel
element:
1 2<web-panel name="DueDateIndicator" ...> ... <label key="due-date-indicator.title"/> </web-panel>
The key
parameter value represents a key in your i18n properties file.
Your app descriptor file should look something like this (comments removed):
1 2<?xml version="1.0" encoding="UTF-8"?> <atlassian-plugin key="${atlassian.plugin.key}" name="${project.name}" plugins-version="2"> <plugin-info> <description>${project.description}</description> <version>${project.version}</version> <vendor name="${project.organization.name}" url="${project.organization.url}"/> <param name="plugin-icon">images/pluginIcon.png</param> <param name="plugin-logo">images/pluginLogo.png</param> </plugin-info> <resource type="i18n" name="i18n" location="tutorial-jira-add-content-to-view-issue-screen"/> <web-resource key="tutorial-jira-add-content-to-view-issue-screen-resources" name="tutorial-jira-add-content-to-view-issue-screen Web Resources"> <dependency>com.atlassian.auiplugin:ajs</dependency> <resource type="download" name="tutorial-jira-add-content-to-view-issue-screen.css" location="/css/tutorial-jira-add-content-to-view-issue-screen.css"/> <resource type="download" name="tutorial-jira-add-content-to-view-issue-screen.js" location="/js/tutorial-jira-add-content-to-view-issue-screen.js"/> <resource type="download" name="images/" location="/images"/> <context>tutorial-jira-add-content-to-view-issue-screen</context> </web-resource> <web-panel name="DueDateIndicator" i18n-name-key="due-date-indicator.name" key="due-date-indicator" location="atl.jira.view.issue.right.context" weight="1000"> <description key="due-date-indicator.description">The DueDateIndicator Plugin</description> <context-provider class="com.example.plugins.tutorial.DueDateIndicator"/> <resource name="view" type="velocity" location="templates/due-date-indicator.vm"/> <label key="due-date-indicator.title"/> </web-panel> </atlassian-plugin>
Save and close the file.
In the same directory, open the i18n properties file called tutorial-jira-add-content-to-view-issue-screen.properties
.
To specify the value of the due-date-indicator.title
key you just defined in your app descriptor, add the
following due-date-indicator.title
property:
1 2due-date-indicator.title=Due Date Indicator
In the Jira View Issue page, this value will appear as the title of your new web panel. Your i18n properties file should look like this:
1 2#put any key/value pairs here my.plugin.name=MyPlugin due-date-indicator.name=DueDateIndicator due-date-indicator.description=The DueDateIndicator Plugin due-date-indicator.title=Due Date Indicator
Save and close the file.
So far, you've created the framework for your web panel plugin module. Now we'll write some Java code that makes the web panel do something interesting. Namely it:
We start with a little refactoring of the code that the SDK gave us.
Navigate to src/main/java/com/example/plugins/tutorial
directory, create and open a new DueDateIndicator.java
file.
1 2package com.example.plugins.tutorial; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.plugin.webfragment.contextproviders.AbstractJiraContextProvider; import com.atlassian.jira.plugin.webfragment.model.JiraHelper; import com.atlassian.jira.user.ApplicationUser; import java.sql.Timestamp; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import static java.time.temporal.ChronoUnit.DAYS; public class DueDateIndicator extends AbstractJiraContextProvider { @Override public Map<String, Object> getContextMap(ApplicationUser applicationUser, JiraHelper jiraHelper) { return null; } }
Notice that it now extends the abstract class AbstractJiraContextProvider and implements the class' getContextMap
method.
The getContextMap
method that we implemented needs to return a Map
object with a key and value that represents the
number of days between the due date and the current date, so that it can be used by other parts of the module.
To do this, initialize a new HashMap
Map
object within the contextMap
method to store this key and value.
1 2Map<String, Object> contextMap = new HashMap<>();
Within the getContextMap
method, initialize a new Jira Issue
object currentIssue
. It will store the current
Jira issue as an object through which you can access its due date as a Java Timestamp
using the getDueDate()
method.
1 2Issue currentIssue = (Issue) jiraHelper.getContextParams().get("issue"); Timestamp dueDate = currentIssue.getDueDate();
Check to see if the current issue's due date has been set and, if so, begin calculating the number of days between the current date and due date. We use Java Date/Time API to calculate days between due date and current date.
1 2if (dueDate != null) { LocalDate currentTimeInDays = LocalDate.now(); LocalDate dueDateTimeInDays = dueDate.toLocalDateTime().toLocalDate(); }
Now that we have the number of days for both the due date time (dueDateTimeInDays
) and current date time
(currentTimeInDays
), we need to calculate the difference between these values.
Associate the daysAwayFromDueDateCalc
value with the keyword daysAwayFromDueDate
using the Map
object
(that is, contextMap
).
Within the if
statement mentioned in the previous step, add the following lines of code:
1 2long daysAwayFromDueDateCalc = DAYS.between(currentTimeInDays, dueDateTimeInDays); contextMap.put("daysAwayFromDueDate", daysAwayFromDueDateCalc);
The DueDateIndicator
class should return the contextMap
Map
object back to your web panel plugin
module to make it available to other resources in your app (that is, Velocity Template resource,
which you will define in the next step). To return the object, add the following line:
1 2return contextMap;
Save the file.
The complete code for DueDateIndicator
should look like this:
1 2package com.example.plugins.tutorial; import com.atlassian.jira.issue.Issue; import com.atlassian.jira.plugin.webfragment.contextproviders.AbstractJiraContextProvider; import com.atlassian.jira.plugin.webfragment.model.JiraHelper; import com.atlassian.jira.user.ApplicationUser; import java.sql.Timestamp; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import static java.time.temporal.ChronoUnit.DAYS; public class DueDateIndicator extends AbstractJiraContextProvider { @Override public Map<String, Object> getContextMap(ApplicationUser applicationUser, JiraHelper jiraHelper) { Map<String, Object> contextMap = new HashMap<>(); Issue currentIssue = (Issue) jiraHelper.getContextParams().get("issue"); Timestamp dueDate = currentIssue.getDueDate(); if (dueDate != null) { LocalDate currentTimeInDays = LocalDate.now(); LocalDate dueDateTimeInDays = dueDate.toLocalDateTime().toLocalDate(); long daysAwayFromDueDateCalc = DAYS.between(currentTimeInDays, dueDateTimeInDays); contextMap.put("daysAwayFromDueDate", daysAwayFromDueDateCalc); } return contextMap; } }
So far, you've written a Java class that retrieves the difference in days between the current issue due date and the current date. Now you will write a Velocity template to present this information in HTML format.
Your web panel plugin module already contains the following context provider:
1 2<context-provider class="com.example.plugins.tutorial.DueDateIndicator"/>
This is your DueDateIndicator
Java class. As already coded, this class returns a Map
object with the property
daysAwayFromDueDate
whose value is the number of days between the current issue's due date and the due
date.
The daysAwayFromDueDate
property is available to other resources in the plugin module, such as the Velocity
template resource that you already defined in the app descriptor using the SDK due-date-indicator.vm
. However, while we
declared it in the descriptor, we still need to add the file.
Navigate to src/main/resources
, create a new templates
directory, and then create a new due-date-indicator.vm
file there.
Add the following if/then/else statement:
1 2#set ($overdueDays = $daysAwayFromDueDate * -1) #if ($daysAwayFromDueDate) #if ($daysAwayFromDueDate > 1) <span style="font-weight: bold; color: green;">This issue is due in $daysAwayFromDueDate days.</span> #elseif ($daysAwayFromDueDate == 1) <span style="font-weight: bold; color: blue;">This is issue is due tomorrow.</span> #elseif ($daysAwayFromDueDate == 0) <span style="font-weight: bold; color: purple;">This issue is due today.</span> #elseif ($daysAwayFromDueDate == -1) <span style="font-weight: bold; color: #ff4500;">This issue was due yesterday!</span> #elseif ($daysAwayFromDueDate < -1) <span style="font-weight: bold; color: red;">This issue is overdue by $overdueDays days!</span> #end #end
This statement provides a colorful visual indicator of when the current issue is due.
Notice that we've defined a new variable called $overdueDays
. Because the daysAwayFromDueDate
property returned by our Java
class contains a negative value whenever an issue is overdue (which is what our if/then/else statement
series relies upon), we've created this new variable to present the value of daysAwayFromDueDate
as a
positive number. Also note that it is a deep-red orange color.
Save the file.
Now you're ready to test your app.
In a new Terminal window, navigate to the project root directory.
Run the following Atlassian Plugin SDK command:
1 2atlas-run
This builds your app code, starts a Jira instance, and installs your app. This could take a few minutes.
Go to localhost:2990/jira in your browser.
Log in using the default admin/admin.
If you use a recent version of Jira, you'll see a wizard for creating a new Jira project. Follow the steps to create one.
Create a new issue, add a due date for it, and then save.
Go to your new issue, and voila! You will see your Due Date Indicator web panel.
Congratulations, that's it!
Have a treat!
To learn more about Jira issues, go to the following pages:
Rate this page: