You're on your way to the next level! Join the Kudos program to earn points and save your progress.
Level 1: Seed
25 / 150 points
Next: Root
1 badge earned
Challenges come and go, but your rewards stay with you. Do more to earn more!
What goes around comes around! Share the love by gifting kudos to your peers.
Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!
Join now to unlock these features and more
The Atlassian Community can help you and your team get more value out of Atlassian products and practices.
I added the following plugins to backend/pom.xml
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>write-project-properties</goal>
</goals>
<configuration>
<outputFile>${project.build.outputDirectory}/maven.properties</outputFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>copy frontend files to resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>src/main/resources/frontend</outputDirectory>
<overwrite>true</overwrite>
<resources>
<resource>
<directory>../frontend/dist</directory>
<includes>
<include>*.*</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
properties-maven-plugin creates a file called maven.properties which contains all maven properties. I need the atlassian.plugin.key property to call the web resource correctly. I will show you later how I use it.
maven-resources-plugin takes JavaScript files from frontend/dist and places these files into backend/resources/frontend.
Next I created a web section called React and two web items called Form and Dynamic Table. I created two servlets and called these servlets from the Form and Dynamic Table web item. Here are the lines from atlassian-plugin.xml:
<servlet name="Form Servlet" i18n-name-key="form-servlet.name" key="form-servlet" class="react.atlaskit.tutorial.servlet.FormServlet">
<description key="form-servlet.description">The Form Servlet Plugin</description>
<url-pattern>/form</url-pattern>
</servlet>
<servlet name="Dynamic Table Servlet" i18n-name-key="dynamic-table-servlet.name" key="dynamic-table-servlet" class="react.atlaskit.tutorial.servlet.DynamicTableServlet">
<description key="dynamic-table-servlet.description">The Dynamic Table Servlet Plugin</description>
<url-pattern>/dynamictable</url-pattern>
</servlet>
<web-section name="React Plugin" i18n-name-key="react.name" key="react" location="admin_plugins_menu" weight="1000">
<description key="react.description">React Plugin</description>
<label key="react.label"/>
</web-section>
<web-item name="from web item" i18n-name-key="form.name" key="form" section="admin_plugins_menu/react" weight="1000">
<description key="form.description">Form</description>
<label key="form.label"/>
<link linkId="configuration-link">/plugins/servlet/form</link>
</web-item>
<web-item name="dynamic table web item" i18n-name-key="dynamictable.name" key="dynamictable" section="admin_plugins_menu/react" weight="1000">
<description key="dynamictable.description">Dynamic Table</description>
<label key="dynamictable.label"/>
<link linkId="configuration-link">/plugins/servlet/dynamictable</link>
</web-item>
So we have our menu items which call our servlets. Now let's have a look at the servlets.
FormServlet.java:
public class FormServlet extends HttpServlet{
private static final Logger log = LoggerFactory.getLogger(FormServlet.class);
private final ResourceService resourceService;
private final SoyTemplateRenderer soyTemplateRenderer;
public FormServlet(@ComponentImport SoyTemplateRenderer soyTemplateRenderer, ResourceService resourceService) {
this.resourceService = resourceService;
this.soyTemplateRenderer = soyTemplateRenderer;
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
String pluginKey = this.resourceService.getProperty("atlassian.plugin.key");
Map<String, Object> map = new HashMap<>();
map.put("contextPath", req.getContextPath());
String html = soyTemplateRenderer.render(pluginKey + ":jira-react-atlaskit-resources", "servlet.ui.form", map);
resp.setContentType("text/html");
resp.getWriter().write(html);
resp.getWriter().close(); }
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StringBuffer jb = new StringBuffer();
String line = null;
try {
BufferedReader reader = req.getReader();
while ((line = reader.readLine()) != null)
jb.append(line);
} catch (Exception e) { /*report an error*/ }
log.info(String.format("Post Data: %s", jb.toString()));
String pluginKey = this.resourceService.getProperty("atlassian.plugin.key");
Map<String, Object> map = new HashMap<>();
map.put("contextPath", req.getContextPath());
String html = soyTemplateRenderer.render(pluginKey + ":jira-react-atlaskit-resources", "servlet.ui.form", map);
resp.setContentType("text/html");
resp.getWriter().write(html);
resp.getWriter().close();
}
}
I define two fields resourceService and soyTemplateRenderer and initialize these fields in the constructor. resourceService is my bean to read maven.properties file. soyTemplateRenderer is a Jira bean to call soy templates.
In the doGet method I get the atlassian.plugin.key property and contextPath. As I said above I need the context path to call this servlet from the Form element on the onsubmit event. Context path contains prefix of you Atlassian Jira url. In my case /jira. Then I pass contextPath as a parameter to my soy template and call servlet.ui.form soy template.
Here is the soy file:
{namespace servlet.ui}
/**
* This template is needed to draw the form page.
*/
{template .form}
{@param contextPath: string}
{webResourceManager_requireResourcesForContext('form')}
<html>
<head>
<meta charset="utf-8"/>
<meta name="decorator" content="atl.admin">
<meta name="admin.active.section" content="admin_plugins_menu/react">
<title>Form Page</title>
</head>
<body>
<div class="field-group hidden">
<input class="text" type="text" id="contextPath" name="contextPath" value="{$contextPath}">
</div>
<div id="maincontainer">
<div id="container">
</div>
</div>
</body>
</html>
{/template}
/**
* This template is needed to draw the dynamic table page.
*/
{template .dynamictable}
{webResourceManager_requireResourcesForContext('dynamictable')}
<html>
<head>
<meta charset="utf-8"/>
<meta name="decorator" content="atl.admin">
<meta name="admin.active.section" content="admin_plugins_menu/react">
<title>Dynamic Table Page</title>
</head>
<body>
<div id="maincontainer">
<div id="container">
</div>
</div>
</body>
</html>
{/template}
As you can see the templates are quite simple. All the templates do is to call required atlassian-plugin.xml web resources and define the div container where react will place all our UI elements.
This soy file was added into atlassian-plugin.xml in the web resource section:
<web-resource key="jira-react-atlaskit-resources" name="jira-react-atlaskit Web Resources">
...
<resource type="soy" name="soyui" location="/templates/servlets.soy"/>
...
<context>jira-react-atlaskit</context>
</web-resource>
And that is all what should be done to use React and Atlaskit in your Atlassian apps.
Alexey Matveev
Rising Starsoftware developer
MagicButtonLabs
Philippines
1,573 accepted answers
3 comments