Level of experience: | Intermediate |
Time to Complete: | Approximately 1 hour 30 minutes |
This tutorial shows you how to display a dialog with content from the server and have it interact with your page. In this tutorial, you'll develop a dialog that sets the version in which an issue should be fixed.
This tutorial adds dialog functionality to already existing app that has:
To display this form in a dialog and have it interact with the page, we'll go through a few different phases.
Simplest Dialog | Adds a JavaScript resource to "slurp" the form content into a dialog using generic methods. |
Standard Dialog | Create a dialog for this specific use case that will work in all circumstances. |
Advanced Dialog | We'll update the underlying page so that we don't need to do a page refresh. |
We encourage you to work through this tutorial. If you want to skip ahead or check your work when you are done, you can find the app source code on Atlassian Bitbucket. Bitbucket serves a public Git repository containing the tutorial's code. To clone the repository, issue the following command to get the completed tutorial code:
1 2git clone https://bitbucket.org/atlassian_tutorial/jira-scheduler-dialog-complete.git
Alternatively, you can download the source using the get source option here: https://bitbucket.org/atlassian_tutorial/tutorial-jira-scheduler.
You should already have installed the following software:
You should also understand the Java development basics including classes, interfaces, methods, how to compile source into a JAR file, and so on.
About these instructions
You can use any supported combination of OS and IDE to construct this app. These instructions were written using Eclipse Classic Version 3.7.1 on a MacBook Air running Mac OS X Version 10.7.2. If you're using another combination, you should use the equivalent operations for your specific environment.
Change directory to your Eclipse workspace.
Download the base tutorial source.
1 2$ git clone https://bitbucket.org/atlassian_tutorial/jira-scheduler-dialog-base.git
Change directory to the app's root directory (where the pom.xml
files is located).
Run some the tests to ensure that the starting point is working.
1 2$ atlas-integration-test
The command builds the code and runs the integration tests that come with the source. Throughout this tutorial, you'll run a number of atlas-
commands that automate much of the work of app development for you. If everything run successfully, you should see a message similar to:
1 2[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 2 minutes 19 seconds [INFO] Finished at: Sat Nov 26 13:26:03 EST 2011 [INFO] Final Memory: 70M/123M [INFO] ------------------------------------------------------------------------
Change to the tutorial-jira-scheduler
directory created by the previous step.
Run the command:
1 2atlas-mvn eclipse:eclipse
Start Eclipse.
Select File > Import.
Eclipse starts the Import wizard.
Filter for Existing Projects into Workspace (or expand the General folder tree).
Select Next and enter the root directory of your workspace.
Your Atlassian app folder should appear under Projects.
Select your app and select Finish.
Eclipse imports your project.
The source files were compiled against the Jira version that existed when the code was created. The version designation is in the project pom.xml
file (Project Object Model definition file). This file is located in the project project and declares the project dependencies. Take a moment and examine the Jira dependency:
Open the pom.xml
file.
Scroll to the bottom of the file.
Find for the <properties>
element.
This section lists the version of the Jira version you selected in Step 1 and also the version of the atlas-
commands you are running.
Enter the Jira version number in the <jira.version>
element. Below, you can see an example for Jira 5.2.
1 2<properties> <jira.version>5.2</jira.version> <amps.version>3.7</amps.version> </properties>
Save the pom.xml
file.
If you change your Atlassian project, Eclipse isn't automatically aware of the changes. Moreover, sometimes your project dependencies require an update. We need to fix that.
Switch to a terminal window.
Change directory to the project root.
This is the directory with the pom.xml
file.
Update the on-disk project metadata with the new POM information.
1 2atlas-mvn eclipse:eclipse
Back in Eclipse, refresh the app project to pickup the changes.
Remember to do this update and refresh step each time you edit your pom.xml
or otherwise modify your app source with an Atlassian command.
At this point, you haven't actually written any Java code. You can however run Jira and see the base app in action. In this step, you'll start Jira, create a project you'll use later, and test the servlet.
Open a terminal window and navigate to the app root folder (where the pom.xml
file is).
Run the following command:
1 2atlas-run
This command builds your app code, starts a Jira instance, and installs your app in it. This may take several seconds. When the process completes, you'll see many status lines on your screen concluding with something like the following lines:
1 2[INFO] jira started successfully in 71s at http://localhost:2990/jira [INFO] Type CTRL-D to shutdown gracefully [INFO] Type CTRL-C to exit
Open your browser and navigate to the local Jira instance started by atlas-run
.
If you followed the instructions, enter http://localhost:2990/jira in your browser.
At the Jira login, enter a username of admin
and a password of admin
.
The integration steps you ran earlier created a project called TEST in your Jira instance. You should have an existing issue called TEST-1 in the Recent Issues category.
Display the TEST-1 issue.
Between the Edit and Assign button, you should see the Schedule button. It launches the app.
Experiment with the issue creation and notice how the button and the resulting dialog behave.
Now, we're ready to start writing some code!
Jira has a feature that allows you to simply add a class to a link in HTML to open the contents of the target page in a dialog. Start Eclipse and do the following:
Edit the atlassian-plugin.xml
file.
Locate the <web-item>
with a key
value of schedule-web-item
.
Add the following styleClass
element as a child element.
1 2<styleClass>trigger-dialog</styleClass>
When you finish, the <web-item
appears as follows:
1 2<web-item name="Schedule Web Item" i18n-name-key="schedule-web-item.name" key="schedule-web-item" section="operations-top-level" weight="3"> <description key="schedule-web-item.description">The Schedule Web Item Plugin</description> <conditions type="and"> <condition class="com.atlassian.jira.plugin.webfragment.conditions.IsIssueEditableCondition"/> <condition class="com.atlassian.jira.plugin.webfragment.conditions.HasIssuePermissionCondition"> <param name="permission" value="edit"/> </condition> <condition class="com.atlassian.jira.plugin.webfragment.conditions.IsFieldHiddenCondition" invert="true"> <param name="field" value="fixVersions"/> </condition> </conditions> <label key="schedule-web-item.label"/> <link linkId="schedule-web-item-link">/secure/SchedulerWebworkModuleAction!default.jspa?id=${issue.id}</link> <styleClass>trigger-dialog</styleClass> </web-item>
Save your changes.
Return to a terminal window and navigate to the app directory.
Enter atlas-debug
at the prompt.
Starting in the debug mode will allow you to use the Fastdev technique.
Open your Jira test instance in a browser and log in.
Open an existing issue (you should have at least one).
Test the Schedule button's behavior.
Selecting the button will bring up the Schedule dialog. When you select Schedule within this dialog, the content of the dialog is submitted to the system.
"Not seeing the Schedule button?"
Ensure the following:
There are issues in the system.
There are versions in the project your issue is in.
You don't have permission to edit the issue.
Keep Jira up and running in your active browser. From this point forward, we'll use the Fastdev approach to test our code changes.
In the previous step, you saw that submitting the form caused the interface to look jumbled. We need to make the server tell the dialog that it can close. There is a convenient method in Webwork Actions that allows you to do this.
Open Eclipse.
Locate the SchedulerWebworkModuleAction.java
file and open it for editing.
Change the doExecute()
method in the class so that it looks returns the following:
1 2/** * The business logic of your form. * Only gets called if validation passes. * * @return the view to display - should usually be "success" */ @RequiresXsrfCheck protected String doExecute() throws Exception { // Business Logic final IssueService.IssueResult update = issueService.update(authenticationContext.getLoggedInUser(), updateValidationResult); if (!update.isValid()) { return ERROR; } // We want to redirect back to the view issue page so return returnComplete("/browse/" + update.getIssue().getKey()); }
If you are following the tutorial, you should still have Jira up and and running.
Go to the browser page and a hard refresh of the page. To do this, you can:
This section discusses what happens behind the scenes in the browser and on the server.
On page load, the app overrides the link's click behavior. We specified this when we added the <styleClass>trigger-dialog</styleClass>
. Instead of following the link, it loads the target page via Ajax and puts the contents in a dialog. We add some URL parameters to the links target to allow the server to know the contents are being rendered in a dialog and they can customize the content.
The URL parameters are:
inline=true | Specifies the content will open in a dialog. |
decorator=dialog | Ensures the content uses the |
The result of any form submision or the target of any links is put into this dialog until the server returns a special response header: X-Atlassian-Dialog-Control:DONE
. Any response header that contains this will close the dialog and refresh the underlying page.
The returnComplete(url)
checks to see if the content is displayed in a dialog. If it is, the system adds the header and returns an empty response. If it is not, it will behave as usual.
You can also redirect to another page when dialog is finished. To do this, instead of closing the dialog and refreshing the current page, you can redirect to another page when the dialog closes. To do this, return X-Atlassian-Dialog-Control:redirect:<url-to-redirect-to>
instead of X-Atlassian-Dialog-Control:DONE
.
To do this in a Webwork Action, edit the SchedulerWebworkModuleAction class to use returnCompleteWithInlineRedirect(<url-to-redirect-to>)
instead of calling returnComplete(...)
.
When using the simplest dialog, you won't be able to customize behavior on dialog close.
For our dialog to work every time, we will need to create a specialized version of a dialog.
In this section, we'll add some JavaScript onto the page that will instantiate the form and bind it to the link. Additionally, we'll use the app module generator, part of the Atlassian Plugin SDK, to generate the stub for our web-resource.
Open a command window and go to the app root folder (where the pom.xml
is located).
Run atlas-create-jira-plugin-module
.
Supply the following information as prompted:
Choose Plugin Module: |
|
Enter Plugin Module Name: |
|
Enter Resource Name: |
|
Enter Resource Type: |
|
Enter Location: |
|
Add Resource Parameter?: |
|
param name: |
|
param value: |
|
Add Resource Parameter?: |
|
Add Resource: |
|
Show Advanced Setup?: |
|
Add Another Plugin Module?: |
|
This will modify your atlassian-plugin.xml
file to include a Web Resource.
In Eclipse, create a folder called javascript
in src/main/resources
.
Add a scheduler.js
file in your new javascript
folder.
Edit scheduler.js
and add the following form:
1 2AJS.$(function () { Jira.Dialogs.scheduleIssue = new Jira.FormDialog({ id: "schedule-dialog", trigger: ".issueaction-schedule-issue", ajaxOptions: Jira.Dialogs.getDefaultAjaxOptions, onSuccessfulSubmit : Jira.Dialogs.storeCurrentIssueIdOnSucessfulSubmit, issueMsg : 'thanks_issue_updated' }); });
Save the file.
Edit the atlassian-plugin.xml
file.
Change the styleClass
element value from trigger-dialog
to issueaction-schedule-issue
as follows:
1 2<styleClass>issueaction-schedule-issue</styleClass>
Add a context
element to the new web-resource element (to allow the new dialog to be visible from all non-administrative pages) as follows:
1 2<context>atl.general</context>
Save the file.
In eclipse, locate the SchedulerWebworkModuleAction.java
file again and open it for editing.
Add a requireResource()
call in the includeResources()
method to register the new scheduler resource:
1 2private void includeResources() { webResourceManager.requireResource("jira.webresources:jira-fields"); webResourceManager.requireResource("com.example.plugins.tutorial.tutorial-jira-scheduler:my-web-resource"); }
Save the file.
Take a minute to examine the file in you examine the new a scheduler.js
file you created in the last step. This code creates a form dialog by specifying the following:
| This is the dialog instance. Any dialogs that live in the namespace |
| The standard form constructor this takes parameters to change it's behavior. |
| A unique DOM id for the dialog. |
| This is what the dialog is bound to. This is usually a jQuery selector. |
| Options that passed to the
|
| The function called after a form was submitted and come back successful. |
| Stores the current issue for later use in the message displayed on page refresh. |
Test out your new code. Reload the app and this form should now work from not only the View Issue page, but also any of the cog menus (Dashboard, Issue Navigator, and the sub-task list). The image below shows the Schedule option in the Issue Navigator:
Ideally, we would want avoid all page refreshes and refresh only the content that was updated. To do this, we'll override the default behavior of the form to write the new versions directly to the field.
In Eclipse, edit scheduler.js
.
Remove the existing form code.
Add the following form code:
1 2AJS.$(function () { // Function for getting the issue key of the issue being edited. var getIssueKey = function(){ if (Jira.IssueNavigator.isNavigator()){ return Jira.IssueNavigator.getSelectedIssueKey(); } else { return AJS.$.trim(AJS.$("#key-val").text()); } }; // Function for getting the project key of the issue being edited. var getProjectKey = function(){ var issueKey = getIssueKey(); if (issueKey){ return issueKey.match("[A-Z]*")[0]; } }; Jira.Dialogs.scheduleIssue = new Jira.FormDialog({ id: "schedule-dialog", trigger: ".issueaction-schedule-issue", ajaxOptions: Jira.Dialogs.getDefaultAjaxOptions, onSuccessfulSubmit : function(){ // This method defines behavior on a successful form submission. // We want to get the versions specified then place them in the view. // This selector gets the container for the FixFor Version for // both a list of issues and the view issue page. var $fixForContainer = AJS.$("#issuerow" + Jira.IssueNavigator.getSelectedIssueId() + " td.fixVersions, #fixfor-val" ); $fixForContainer.html(""); // Blank out the existing versions. // Now lets construct the html to place into the container. var htmlToInsert = ""; // this.getContentArea() return the contents of the dialog. From this we will get teh selected values of the select list and iterate over them. this.getContentArea().find("#fixVersions option:selected").each(function(){ var $option = AJS.$(this); // We want to comma separate them. if (htmlToInsert !== ""){ htmlToInsert += ", "; } var versionName = AJS.$.trim($option.text()); // Construct the link and append it to the html. htmlToInsert += "<a href='" + contextPath + "/browse/" + getProjectKey() + "/fixforversion/" + $option.val()+ "' title='" + versionName + "'>" + versionName + "</a>"; }); // If no options were selected, insert none. if (htmlToInsert === ""){ htmlToInsert = AJS.I18n.getText("common.words.none"); } // Set the html of the container. $fixForContainer.html(htmlToInsert); }, onDialogFinished : function(){ // This function is used to define behavior after the form has finished. // We want to display a notification telling people that the fix version was updated. // When displayed in the Issue Navigator also show the issue key of the issue updated. if (Jira.IssueNavigator.isNavigator()){ Jira.Messages.showSuccessMsg(AJS.I18n.getText("scheduler.success.issue", getIssueKey())); } else { Jira.Messages.showSuccessMsg(AJS.I18n.getText("scheduler.success")); } }, autoClose : true // This tells the dialog to automatically close after a successful form submit. }); });
Save your work.
To test the app:
Switch to a terminal window.
If Jira is running, stop it.
Change directory to the project root.
This is the directory with the pom.xml
file.
Update the on-disk project metadata with the new POM information.
1 2atlas-mvn eclipse:eclipse
Start Jira by running atlas-debug
.
Log in to Jira and test the new, advanced Schedule dialog.
Congratulations!
You should now have a fully working dialog.
Rate this page: