Feel free to open issues / pull requests in case of questions / errors on this exercise
Duration |
Between 1 and 2 days |
---|---|
Skills |
Javascript / Typescript, React, REST API |
License |
|
Repository |
Changelog
Date | Summary |
---|---|
2021-09-13 |
Document creation |
2022-02-23 |
Updating deprecated scopes |
1. Prerequisites
Before starting this exercise, be sure to:
-
Read and apply instructions from the Getting started page on the Forge documentation website;
-
Follow at least one of these two tutorials:
At this point, we expect the following to be the case:
|
2. About this exercise
The main purpose of this exercise is to explore the main Forge features by creating a simple Jira application that adds generated user information on Jira issues.
And what about Confluence ? |
Here is the plan: first thing to do is create an administration page, to allow users configuring our application.
Once it’s done, we will listen to issue creations in Jira by using the trigger
mechanism.
Then, when an issue is created, we will retrieve our application settings from the Forge storage
and fetch
a remote API to retrieve our user information and store them into the created issue.
Finally, the information will be rendered inside the issue, using an issue panel
.
The exercise is split into 4 parts:
-
Set up the Forge application;
-
Create the application administration;
-
Configure the issue creation trigger;
-
Display the user information in the issue;
At the end of each part (except the Forge setup), you will be asked to implement a solution by yourself. However, a solution is available in this repository if needed.
These exercises will require you to explore the Forge documentation to understand and discover Forge capabilities. If needed, don’t hesitate to ask for help on the Atlassian Developer Community. |
3. Let’s code!
3.1. Setup the Forge application
First thing to do is creating our application by using the Forge CLI
:
forge create random-user
This command shows you various templates to start a new Forge app.
Select Custom UI
, then jira-issue-panel
by using arrow keys, and press Enter :
Start with a template. Each template contains the required files to be a valid app. ? Select a category: Custom UI ? Select a template: jira-issue-panel ✔ Creating app... ℹ Downloading template ℹ Registering app ℹ Creating environments ℹ Installing dependencies ✔ Created cat-tachment Your app is ready to work on, deploy, and install. We created 3 environments you can deploy to: development, staging, production. Change to directory random-user to see your app files.
This template contains files which will be useful in the last part (Custom UI). Now, if you navigate to the Forge Developer Console, you should see your newly created app.
To continue the setup, go to the ./static/hello-world/
folder, and run the following command:
npm install
npm run build
This part is required to start your Forge app and will be explained later, in the Custom UI part.
Ignore it for now and go back to the top of your app directory (cd ../..
).
Let’s see files generated by the Forge CLI:
-
./src
folder which contains code relative to Forge functions and UI Kit-
index.tsx
you can ignore its content for now (since it related to the issue view / Custom UI)
-
-
./static
same, you can ignore for now -
manifest.yml
is the file describing your app
Let’s focus on the manifest.yml
file and its different parts:
modules:
jira:issuePanel: (1)
- key: random-user-hello-world-panel
resource: main
resolver:
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
function: (2)
- key: resolver
handler: index.handler
resources: (3)
- key: main
path: static/hello-world/build
app: (4)
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
1 | modules are locations inside Atlassian products where your app can be displayed.
The current module allows our app to appear in the Jira issue. |
2 | function allows you to define Javascript function as Forge functions.
They are used by modules entries to display content.
The key property is a unique identifier for the function, and the handler is the "path" to the function. Here, we ask the function handler from the file ./src/index.js . |
3 | resources are used by Custom UI (so, let’s see this later) |
4 | app is used to identify your app in the Atlassian Forge infrastructure. |
|
We will add other properties soon in this exercise.
Resource
All available properties of the |
Now, let’s start creating our administration!
3.2. Create the administration
Let’s build our administration with UI kit. This part of Forge allow you to declare graphical interface using components provided by Atlassian (and only them). And before starting, some setup (again).
Resource
Documentation about UI kit (components, hooks, event) can be found on the Forge documentation. |
3.2.1. Adding Typescript
To add Typescript in the UI Kit part of our project, we simply need to run:
npm install typescript @types/node @types/react
and add the tsconfig.json
file in our app folder:
{
"compilerOptions": {
"module": "commonjs",
"target": "es2017",
"sourceMap": true,
"moduleResolution": "node",
"esModuleInterop": true,
"lib": ["dom", "es2017"],
"types": ["node", "react"],
"baseUrl": "./",
"allowJs": true,
"jsx": "react",
"jsxFactory": "ForgeUI.createElement"
},
"include": ["./src/**/*"]
}
3.2.2. Declaring our administration
Now, we have to declare our administration in the manifest.yml
.
Before that, let’s create the function responsible for rendering our administration.
In ./src
, create the file administration.tsx
with the following content:
import ForgeUI, {AdminPage, render, Text} from '@forge/ui';
const App = () => {
return (
<AdminPage> (1)
<Text>Hello, world!</Text>
</AdminPage>
);
};
export const run = render(
<App/>
);
1 | Since we want to be displayed as an admin page, our root component have to be <AdminPage> .
Each module has its own rooter component to use. |
Install the missing dependency (which contains UI kit)
npm install @forge/ui
And now, it’s time to declare the run
function from our administration.tsx
file.
Open the manifest.yml
and add the following content:
modules:
jira:issuePanel:
- key: random-user-hello-world-panel
resource: main
resolver:
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
jira:adminPage: (2)
- key: random-user-administration
function: run-administration
title: Random user administration
function:
- key: resolver
handler: index.handler
- key: run-administration (1)
handler: administration.run
resources:
- key: main
path: static/hello-world/build
app:
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
1 | First thing to do is declaring our function |
2 | Then, we need to tell Forge we want to be displayed in a Jira administration page |
3.2.3. Time to deploy and test!
Now, we should have a something working, let’s test that.
Since it’s our first run, we have to execute the forge deploy
command to upload our manifest.yml
and Forge functions to Forge infrastructure.
Then, let’s install our app on a real Jira Cloud instance.
Run the forge install
command, select Jira
and type your Atlassian Cloud instance URL.
? Select a product: Jira
Enter your site. For example, your-domain.atlassian.net
? Enter the site URL: your-instance.atlassian.net
Installing your app onto an Atlassian site.
Press Ctrl+C to cancel.
Your app will be installed with the following scopes:
- read:me
? Do you want to continue? Yes
✔ Install complete!
Your app in the development environment is now installed in Jira on your-instance.atlassian.net
Now, navigate to your Jira instance, open settings (top-left menu) and select "Apps". You should see your app on the left side menu. Click on it, the app is loading and should greet you (and the world)
3.2.4. Updating the app
Instead of using forge deploy
after editing our administration, we can use forge tunnel
.
For Mac with ARM processor you will have to use this hack in order to be able to use forge tunnel. |
This command will update your app each time a change is detected. Ensure Docker is running on your computer, then run the command:
$ forge tunnel
Tunnel redirects requests you make to your local machine. This occurs for any Atlassian site where your app is installed in the development environment. You will not see requests from other users.
Press Ctrl+C to cancel.
Checking Docker image... 100%
Your Docker image is up to date.
Reloading code...
=== Running forge lint...
No issues found.
=== Bundling code...
App code bundled.
=== Snapshotting functions...
No log output.
App code reloaded.
Listening for requests...
Now, if you refresh the page where your application is displayed, the Forge tunnel should detect the request:
invocation: 3e300f372fab08cb administration.run
Try adding a component to your administration.tsx
:
<AdminPage>
<Text>Hello, world!</Text>
<Text>No forge deploy needed!</Text>
</AdminPage>
And refresh your page: the new line of text should appear.
3.2.5. Real things start
The setup is now over, it’s time to implement our administration.
You have to do this part by yourself, using the resources below.
An implementation is available in the ./typescript/random-user
directory of this repository.
You can use it to compare your solution or as a little help.
What you must do:
In the next part, we will use the randomuser.me API to generate random user information.
Using URL parameters, it’s possible to act on generated information.
Our administration will simply allow our user to set the gender which will be generated.
The API option values are male
and female
, but you must allow your user to also select a random
option in your administration.
The selected choice must be loaded and saved using the Forge Storage
API, because in the next part, the trigger will rely on it.
Resources:
-
UI kit guide (how to use components, hooks and events)
-
UI kit components (available components - you cannot create your own)
-
Storage API (how to use)
Additional notes:
-
Everything can be done in the
administration.tsx
file; -
Don’t forget to install
@forge/api
to use storage; -
You can use any components you want (radio, dropdown, button group, …) to collect user choice;
-
Check the tunnel output, some errors and associated fix will be displayed here;
-
To apply changes relative to Forge permissions, run
forge depoy
thenforge install --upgrade
; -
If you use
console.log
, logs will be displayed in the Forge tunnel, and not the browser
And now, it’s trigger time.
3.3. Listening for issue creations
The next part of the exercise is listening for a new issue and attaching generated user information on it. Regarding Typescript, the previous configuration is reused, so no additional steps.
3.3.1. A trigger?
Triggers are functions called when a specific event occurs on an Atlassian product. For example your can listen for Confluence page creation or Jira mentions on issues. Once the event is triggered, Forge calls your function with all the details, and you can do your business.
Resource
Documentation about Forge triggers can be found on the Forge documentation. |
3.3.2. Declaring a Forge trigger
Previously we used the manifest.yml
to declare our administration.
Guess what? Still the same way for triggers:
modules:
jira:issuePanel:
- key: random-user-hello-world-panel
resource: main
resolver:
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
jira:adminPage:
- key: random-user-administration
function: run-administration
title: Random user administration
trigger: (2)
- key: issue-created-event (3)
function: issue-created
events:
- avi:jira:created:issue (4)
function:
- key: resolver
handler: index.handler
- key: run-administration
handler: administration.run
- key: issue-created (1)
handler: trigger.run
resources:
- key: main
path: static/hello-world/build
app:
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
permissions:
scopes:
- storage:app (5)
- read:issue:jira (6)
- read:issue-type:jira
- read:user:jira
- read:project:jira
- read:status:jira
1 | First, we define the function which will be called when the event occurs |
2 | We add the trigger section |
3 | and the entry for our associated function |
4 | Finally, we indicate the events we want to listen to |
5 | This permission was added for the administration part and will also be required for our trigger (nothing to add) |
6 | These permissions are required by the avi:jira:created:issue event. We will talk about permissions right after this part. |
Don’t forget to create the ./src/trigger.ts
file (no need to add .tsx
since the trigger doesn’t return graphical content).
You should also add the following content, to match our previous declaration in the manifest.yml
file.
export async function run(event, context) {
console.log('Here is the content of the event:');
console.log(JSON.stringify(event, null, 4));
}
The event
parameter contains information related to the received event.
So content for a Confluence page created and a Jira issue created are not the same.
Now, run forge deploy
to declare the trigger, upgrade your installation using forge install --upgrade
since permissions changed and run forge tunnel
to watch executions and logs.
Then, create a Jira project on your instance (or use an existing one), and create a new issue.
The forge tunnel should display something like:
invocation: 805279f4da83daeb trigger.run
INFO 11:49:25.739 805279f4da83daeb Here is the content of the event:
INFO 11:49:25.740 805279f4da83daeb {
"issue": {
"id": "10046",
"key": "JIR-37",
"fields": {
"summary": "Trigger test !",
"issuetype": {
"self": "https://your-instance.atlassian.net/rest/api/2/issuetype/10001",
"id": "10001",
"description": "Functionality or a feature expressed as a user goal.",
"iconUrl": "...",
"name": "Story",
"subtask": false,
"avatarId": 10315,
"hierarchyLevel": 0
},
"creator": {
"accountId": "5bccf2f82bfc57158b2faa60"
},
"created": "2021-10-20T13:49:24.537+0200",
"project": {
"self": "https://elements-cga.atlassian.net/rest/api/2/project/10000",
"id": "10000",
"key": "JIR",
"name": "Jiraya",
"projectTypeKey": "software",
"simplified": false,
"avatarUrls": {...}
},
"reporter": {
"accountId": "5bccf2f82bfc57158b2faa60"
},
"assignee": null,
"updated": "2021-10-20T13:49:24.537+0200",
"status": {
"self": "https://your-instance.atlassian.net/rest/api/2/status/10000",
"description": "",
"iconUrl": "https://your-instance.atlassian.net/",
"name": "Backlog",
"id": "10000",
"statusCategory": {
"self": "https://your-instance.atlassian.net/rest/api/2/statuscategory/2",
"id": 2,
"key": "new",
"colorName": "blue-gray",
"name": "To Do"
}
}
}
},
"atlassianId": "5bccf2f82bfc57158b2faa60",
"associatedUsers": [
{
"accountId": "5bccf2f82bfc57158b2faa60"
}
]
}
In these logs, we can see who created the issue and various fields with their content (id, key, project info, …).
3.3.3. About permissions
Before coding the trigger part, we must talk about permissions in Forge apps. There are various type of permissions, as listed here:
-
Permissions for using some Forge API, like the storage one (you used it earlier)
-
Permissions to access some product parts, especially when using product REST API
-
Permissions to access external contents. By default you can’t talk with the entire internet, without asking user permissions
Some of these permissions are displayed to the administrator when they are installing your app, others are displayed directly to the end user (if your request concerns personal data for example).
Remember, when you add a new permission you have to redeploy your app (forge deploy
) and upgrade existing installations using forge install --upgrade
for changes to take effect.
3.3.4. Now, exercise time
Like for the administration, the implementation is up to you again!
A possible implementation is available in ./typescript/random-user/src/trigger.ts
for help / comparing your solution.
What you must do:
When an issue is created, retrieve the settings in the forge storage. Then, request https://randomuser.me/api to generate random user information. You must take in account the user choice concerning the gender. For more information about the gender parameter, check the randomuser documentation.
The goal is to store the information received from the API into the issue, by using Jira Properties, to retrieve it later.
randomuser.me is a free service, however you can support project with a donation on the website. |
Resources:
-
Jira created issue event (with event data example)
-
Calling internal & external API (to request randomuser and Jira)
Additional notes:
-
Again, watch out for permissions
-
Take in account that the storage can be empty if the user hasn’t used the administration yet.
-
Don’t forget to use
route
withrequestJira
-
You can also work with Jira Properties through REST API
Next step, Custom UI!
3.4. Display user information in Jira issue
To conclude this exercise, we will display our generated user into a Jira issue. Instead of UI kit, we will use Custom UI, the second way to build a graphical interface using Forge.
Custom UI is a more open way to build the front part than UI kit. In fact, you can use anything (languages and technologies) you want. The only thing Forge require in the end is static assets (HTML, CSS, JSS, …).
When we created our Forge app at the beginning of this exercise, we used a Custom UI template. Now it’s time to dig into all the "we will see this later" things.
Resource
Documentation about Custom UI can be found on the Forge documentation. |
3.4.1. Custom UI: how does this work?
If you check the ./static/hello-world
directory, you will see a standalone React project.
In fact, this was generated by the Forge template we used previously.
The project you see is based on create-react-app, which provides a ready-to-use React application.
To be recognized as a "Custom UI project", you must declare a resources
in the manifest.yml
.
Hopefully, everything is ready thanks to the Forge template:
modules:
jira:issuePanel:(2)
- key: random-user-hello-world-panel
resource: main
resolver: (3)
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
jira:adminPage:
- key: random-user-administration
function: run-administration
title: Random user administration
trigger:
- key: issue-created-event
function: issue-created
events:
- avi:jira:created:issue
function:
- key: resolver
handler: index.handler
- key: run-administration
handler: administration.run
- key: issue-created
handler: trigger.run
resources: (1)
- key: main
path: static/hello-world/build
app:
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
permissions:
scopes:
- storage:app
- read:issue:jira
- read:issue-type:jira
- read:user:jira
- read:project:jira
- read:status:jira
external:
fetch:
backend:
- https://randomuser.me (4)
1 | Our resource "main" is declared here.
The path tells Forge where static assets of our Custom UI can be found.
In our case, the output build directory of our hello-world React application is provided. |
2 | This part was generated before using forge create , so Forge knows we want to be displayed in an Jira issue panel |
3 | We tell Forge which function will be used to handle communication with our Custom UI project.
This function is also declared in the function part. |
4 | Permissions added before to fetch the randomuser.me API |
Let’s dig in the ./src/index.js
file, which is declared as our resolver
:
import Resolver from '@forge/resolver';
const resolver = new Resolver(); (1)
resolver.define('getText', (req) => { (2)
console.log(req);
return 'Hello, world!';
});
export const handler = resolver.getDefinitions(); (3)
1 | A resolver is created here. It will contain functions accessible in our Custom UI project. |
2 | Here, we define the getText function. The req parameter will contain context about the invocation and also arguments used to call this function. |
3 | Finally, all functions defined in the resolver are exported |
This was for the "Forge side", not let’s see how it’s work in our Custom UI project by opening ./src/static/hello-world/src/App.js
:
import React, { useEffect, useState } from 'react';
import { invoke } from '@forge/bridge'; (1)
function App() {
const [data, setData] = useState(null);
useEffect(() => {
invoke<string>('getText', { example: 'my-invoke-variable' }).then(response => setData(response)); (2)
}, []);
return (
<div>
{data ? data : 'Loading...'}
</div>
);
}
export default App;
1 | We retrieve the invoke method from the @forge/bridge package, which allow us to call functions defined in the previous resolver |
2 | Here we call the getText method we declared before. We should receive a javascript Promise with the Hello, world! content. |
So, what is this @forge/bridge
?
Custom UI has no access to the Forge world by default.
This means you can’t directly use packages like @forge/api
, contrary to previous parts.
This is where @forge/bridge
is helpful: as indicated in the name, this package allows you to create a "bridge" between a Custom UI project and our Forge functions.
This way, you can continue to use all Forge features.
Let’s do a simple test.
Go to your jira instance and open an issue.
You should see the Atlassian logo under the issue name.
Click on it, and your instance will ask you to allow the app to access Jira in a new tab.
You can see that displayed permissions match our manifest.yml
.
Click on "Accept", and the app should be displayed:
As you can see, the "Hello, world!" text from our Forge function is displayed. Here is what happens:
Now, some setup before starting the final part of this exercise.
3.4.2. Adding Typescript
If you check our ./src
folder, you can see that index.js
doesn’t use Typescript.
Since Typescript is already configured in this directory, you can rename this file to index.ts
.
|
Now regarding our Custom UI project in ./src/static/hello-world
, no Typescript is available here.
Let’s add it using the following command:
npm install typescript @types/node @types/react @types/react-dom
The |
Once it’s installed, we can replace .js
extension of files in ./src/static/hello-world/src
with the .tsx
one.
Like previously, we need to create the tsconfig.json
file in ./src/static/hello-world
with this content:
{
"compilerOptions": {
"target": "es2017",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"downlevelIteration": true
},
"include": [
"src"
]
}
Typescript should find errors in App.tsx
, so you can replace its content with this one:
import React, { useEffect, useState } from 'react';
import { invoke } from '@forge/bridge';
function App() {
const [data, setData] = useState<string>();
useEffect(() => {
invoke('getText', { example: 'my-invoke-variable' }).then((response) => setData(response as string));
}, []);
return (
<div>
{data ? data : 'Loading...'}
</div>
);
}
export default App;
3.4.3. Working with Forge tunnel and hot reload
Now, each time we modify our Custom UI project, we need to run npm run build
to generate our assets inside the ./build
folder, then run forge deploy
to send assets on the Forge infrastructure.
As you see, it takes something like 1 minute to run these two commands.
When developing, this will be a problem.
That why Forge allow you to bind a local development server to the Forge tunnel.
Luckily, create-react-app
comes with a dev server! What a good break 👀
Let’s start the server by running this command in ./static/hello-world
:
npm start
Now, each time we edit something in our Custom UI project, the assets will be regenerated and available at http://localhost:3000/. If you try to reach this address, you should receive this error:
Uncaught Error:
Unable to establish a connection with the Custom UI bridge.
If you are trying to run your app locally, Forge apps only work in the context of Atlassian products. Refer to https://go.atlassian.com/forge-tunneling-with-custom-ui for how to tunnel when using a local development server.
It’s expected: the @forge/bridge
package only works on an Atlassian instance.
Then, we must tell Forge tunnel to use our web server to serve our Custom UI content. For this, the Atlassian documentation is clear:
modules:
jira:issuePanel:
- key: random-user-hello-world-panel
resource: main
resolver:
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
jira:adminPage:
- key: random-user-administration
function: run-administration
title: Random user administration
trigger:
- key: issue-created-event
function: issue-created
events:
- avi:jira:created:issue
function:
- key: resolver
handler: index.handler
- key: run-administration
handler: administration.run
- key: issue-created
handler: trigger.run
resources:
- key: main
path: static/hello-world/build
tunnel: (1)
port: 3000
app:
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
permissions:
scopes:
- storage:app
- read:issue:jira
- read:issue-type:jira
- read:user:jira
- read:project:jira
- read:status:jira
external:
fetch:
backend:
- https://randomuser.me
1 | We just need to add the tunnel property under our Custom UI resource. Last thing to add is the port to listen, in our case 3000. |
Now, forge deploy
the changes, run forge tunnel
and open (or reload) an issue view on your Atlassian instance.
If it’s working, you should see these logs:
Received proxy request. Serving file index.html for resource main from specified address http://localhost:3000 (1)
CSP violation detected for 'style-src' while serving content at http://localhost:8001/
For an app to share data with external resources or use custom CSP, follow the steps in: https://go.atlassian.com/forge-content-security-and-egress-controls (2)
1 | This line indicates that the content is served from your local dev server |
2 | The second is related to a Content Security Policy (CSP) issue. |
3.4.4. Handling CSP
Our Custom UI project has some restrictions regarding the Forge security requirement.
As noted by the previous log, our React app generate <style>
in the served index.html
, which by default is not allowed by Forge.
To avoid CSP, edit the manifest with the following content:
modules:
jira:issuePanel:
- key: random-user-hello-world-panel
resource: main
resolver:
function: resolver
viewportSize: medium
title: random-user
icon: https://developer.atlassian.com/platform/forge/images/issue-panel-icon.svg
jira:adminPage:
- key: random-user-administration
function: run-administration
title: Random user administration
trigger:
- key: issue-created-event
function: issue-created
events:
- avi:jira:created:issue
function:
- key: resolver
handler: index.handler
- key: run-administration
handler: administration.run
- key: issue-created
handler: trigger.run
resources:
- key: main
path: static/hello-world/build
tunnel:
port: 3000
app:
id: ari:cloud:ecosystem::app/9513507c-5fa1-4e5e-8fee-a5d7ef17a07e
permissions:
scopes:
- storage:app
- read:issue:jira
- read:issue-type:jira
- read:user:jira
- read:project:jira
- read:status:jira
content: (1)
styles:
- 'unsafe-inline'
external:
fetch:
backend:
- https://randomuser.me
1 | We tell Forge we need to allow inline CSS |
Now, in the ./src/static/hello-world/public/index.html
file, add the following line:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="Content-Security-Policy" content="style-src 'self' 'unsafe-inline'" /> (1)
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
1 | We also add the CSP part in our Custom UI project |
Since we edit permissions, remember to forge deploy
and forge install --upgrade
.
After reloading the issue view, our app should be displayed correctly.
Try editing App.tsx
by adding some text: after saving, your app is directly updated.
Resource
You can find more information about Forge CSP in the Forge documentation. |
3.4.5. Final exercise
Time to shine! As usual, do it yourself, solution available if needed in the App.tsx
file.
What you must do:
First thing to do is retrieve user information we stored previously in the Jira Issue Properties.
Two ways are available to perform this: by invoke`ing a function defined in the resolver or using `requestJira
method (also from the @forge/bridge
package).
Once the data are retrieved, try to display simple information like the generated user picture, it’s name and email.
Resources:
Additional notes:
-
Don’t forget to start your Forge tunnel and dev server
-
Using the
requestJira
of@forge/bridge
perform the request "as the current user" and not in the name of your app. -
Make sure to check permissions required by the Atlassian API you’re using
-
You can use Atlaskit components to provide an Atlassian-like user experience. Make sure to manage this case.
-
Sometime, some errors can be solved by restarting the Forge tunnel / dev server
-
Displaying images from randomuser.me will require additional egress permission
Once it’s done: run npm run build
in ./src/static/helloword
to create an optimized build of your Custom UI project, then run forge deploy
.
Now you can access your app without using Forge tunnel.
4. Next steps
The goal of this exercise is to cover some interesting features of the Forge framework, but a lot remains. To go further:
-
For the administration part, you can add others API options, like seed, nationality, password, … then take these options in account when the trigger is invoked.
-
Speaking of the trigger part, you could use the Forge Storage to store a history of last 10 generated users. This history could also be displayed in the administration as a table containing the ID of the issue and the first and last name of the user. Regarding how you store the data in the Forge Storage, you would be interested in the query part.
-
In our issue panel, you can add a "refresh" button to generate a new user and replace the existing one, using a function from the resolver.
-
Check the Forge Environments. We juste used the
development
one, but you will have to useproduction
if you want to share your app. You can also push an app to the Atlassian Marketplace, but be aware of Forge quotas and limits; -
You can also play with Display Conditions, to limit access to our previous issue panel.