UP | HOME
Ravi Sagar | Home | Blog

Create hello world app using Forge

Table of Contents

1 Create the app

  • Navigate to the directory where you want to create the app
forge create
  • Enter the name of the app: hello-world-app
  • Select a category: UI kit
  • Select a template: jira-issue-panel

A new folder will be created.

cd hello-world-app

2 jira-issue-panel template

ls hello-world-app

3 Change the panel title

Go to the manifest.yml and modify the title.

4 Install the app

Run this command from the top level directory.

forge deploy

Then install the app.

forge install

Select a product: Jira Enter the site URL: abc-dev.atlassian.net Then continue.

5 Check your app

Go to Manage apps section of your Jira instance and you will find your app installed on the instance.

Now create an issue in a project, create a project if not already done. You will find a button on top called Forge app for Ravi or whatever title you used in the manifest.yml file above.

Cool isn't it? How long it took you to create, deploy and install the app?

6 Further changes to the app.

You can do that using forge deploy. So let us say you change the title, so after you run this command the changes will be reflected back.

This is a manual way of deploying the changes.

First make sure docker is running.

sudo systemctl start docker

Then run forge tunnel.

6.1 TODO For me it didn't work properly. If I run docker with sudo then it works but not with normal user. Not a big problem because I can always use forge deploy.

7 Calling Jira API

Now instead of display a static text, let us consume and end point.

7.1 Install @forge/api

npm install @forge/api

7.2 Make changes in your code

7.3 Run forge tunnel if not running already

When you add comments and refresh your page then you will see a message in your console showing number of comments.

7.4 Forge might ask to update permission.

If Forge complains about the permissions just follows its instructions.

7.5 Show last comment

Modify the code from Atlassian to display last comment along with number of comments.

const fetchLastCommentForIssue = async (issueId) => {
  const res = await api
    .asApp()
    .requestJira(`/rest/api/3/issue/${issueId}/comment`);

  const data = await res.json();
  if (data.comments.length==0) {
    return "No comments yet, be the first one!"
  } else {
    const numberOfComments = data.comments.length
    const lastComment = data.comments[numberOfComments-1].body.content[0].content[0].text
    console.log(lastComment);
    return lastComment;
  }
};

8 Make API calls on behalf of a user

In your index.jsx file change .asApp() to .asUser(). So your function will look like this.

const fetchLastCommentForIssue = async (issueId) => {
  const res = await api
    .asUser()
    .requestJira(`/rest/api/3/issue/${issueId}/comment`);

  const data = await res.json();
  if (data.comments.length==0) {
    return "No comments yet, be the first one!"
  } else {
    const numberOfComments = data.comments.length
    const lastComment = data.comments[numberOfComments-1].body.content[0].content[0].text
    console.log(lastComment);
    return lastComment;
  }
};

Now just run sudo forge tunnel again and refresh the issue. You will get a button to allow access.

9 Forge logs

If you run forge logs then you can check the recent log items. Can be helpful for debugging.

INFO    2021-03-28T14:09:01.909Z e4d5f610-047b-4e01-9942-813e53732c20 Number of
comments on this issue: 4
INFO    2021-03-28T14:10:18.192Z f2b0e068-aa1a-40e0-b3f3-8f999a443158 Number of
comments on this issue: 4
INFO    2021-03-28T14:10:50.324Z 8b63305e-cf41-4d13-ad6b-a915da77c15f Number of
comments on this issue: 4
INFO    2021-03-28T14:11:27.599Z 605b4de8-70e4-473a-b160-a465dbdcf49b Number of
comments on this issue: 4

10 Display current project's name

Let us display current issue's project name as well in the panel.

const fetchProjectFromIssue = async (issueId) => {
  const res = await api
    .asUser()
    .requestJira(`/rest/api/3/issue/${issueId}`);

    const data = await res.json();

    return data.fields.project.name;

};
//call this method to get the value
  const projectName = useState(async ()=> await fetchProjectFromIssue(context.platformContext.issueKey));

This is how your code will look like now.

import ForgeUI, { render, Fragment, Text, IssuePanel, useProductContext, useState } from '@forge/ui';

const App = () => {
  const context = useProductContext();
  const [comments] = useState(async () => await fetchCommentsForIssue(context.platformContext.issueKey));
  const lastComment = useState(async ()=> await fetchLastCommentForIssue(context.platformContext.issueKey));
  const projectName = useState(async ()=> await fetchProjectFromIssue(context.platformContext.issueKey));

  const message = `Number of comments on this issue: ${comments.length}`;
  console.log(message);
  console.log(lastComment);
  console.log(projectName);

  return (
    <Fragment>
      <Text>Hello world! Great it works.</Text>
      <Text>{message}</Text>
      <Text>{lastComment[0]}</Text>
      <Text>{projectName[0]}</Text>
    </Fragment>
  );
};

export const run = render(
  <IssuePanel>
    <App />
  </IssuePanel>
);

const fetchCommentsForIssue = async (issueId) => {
  const res = await api
    .asUser()
    .requestJira(`/rest/api/3/issue/${issueId}/comment`);

  const data = await res.json();
  return data.comments;
};


const fetchLastCommentForIssue = async (issueId) => {
  const res = await api
    .asUser()
    .requestJira(`/rest/api/3/issue/${issueId}/comment`);

  const data = await res.json();
  if (data.comments.length==0) {
    return "No comments yet, be the first one!"
  } else {
    const numberOfComments = data.comments.length
    const lastComment = data.comments[numberOfComments-1].body.content[0].content[0].text
    console.log(lastComment);
    return lastComment;
  }
};

const fetchProjectFromIssue = async (issueId) => {
  const res = await api
    .asUser()
    .requestJira(`/rest/api/3/issue/${issueId}`);

    const data = await res.json();

    return data.fields.project.name;

};

11 Forge tunnel debug

Run forge tunnel debug and open the url to check debugging. Add debugger; in your code as well before that.