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
software developer
MagicButtonLabs
Philippines
1,575 accepted answers
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
4 comments