Bryntum
28 April 2023

How to connect and sync Bryntum Task Board to Jira

With Bryntum TaskBoard, you can build a fully customizable TaskBoard with pure JavaScript. You can easily use Bryntum TaskBoard with React, […]

With Bryntum TaskBoard, you can build a fully customizable TaskBoard with pure JavaScript. You can easily use Bryntum TaskBoard with React, Vue, or Angular.

In this tutorial, we’ll connect and sync Bryntum TaskBoard to Atlassian’s Jira software. We’ll do the following:

Getting started

Clone the starter GitHub repository. This starter repository uses development server and JavaScript bundler Vite. You’ll need Node.js version 14.18+ for Vite to work.

Install the Vite dev dependency by running the following command:

npm install

The dev server is configured to run on http://localhost:8080/ in the vite.config.js file. Run the local dev server now using npm run dev and you’ll see a blank page.

Create a task board using Bryntum TaskBoard

We’ll install the Bryntum TaskBoard component using npm. Follow step one of the Bryntum TaskBoard set up guide to log into the Bryntum registry component.

Then initialize your application using the npm CLI command:

npm init

You will be asked a series of questions in the terminal; accept all the defaults by pressing the enter key for each question.

Now follow step four of the Bryntum TaskBoard set up guide to install Bryntum TaskBoard.

Let’s import the Bryntum TaskBoard component and give it some basic configuration. In the index.js file, add the following lines:


import { TaskBoard } from '@bryntum/taskboard/taskboard.module.js';
 
const taskBoard = new TaskBoard({
    appendTo : document.body,
    columnField : 'status',
    columns : [
        'todo',
        'doing',
        'done'
    ],
    project : {
        tasksData : [
            { id : 1, name : 'My first task', status : 'doing' },
            { id : 2, name : 'My second task', status : 'todo' }
        ]
    }
});

Here we import Bryntum TaskBoard, create a new Bryntum TaskBoard instance, and pass a configuration object into it. We add the TaskBoard to the <body> of the DOM.

We pass in data inline to populate the project tasksData for simplicity. We have two task items within it. You can learn more about working with data in the Bryntum docs.

If you run your dev server now, you’ll see the items in our Bryntum TaskBoard:

Our TaskBoard chart uses the Stockholm theme, which is one of five available themes for Bryntum TaskBoard. We’ve linked to the CSS for the Stockholm theme in index.html. If you’d like to create a custom theme, read more about styling your TaskBoard in our customization documentation.

Now let’s learn how to retrieve a list of Jira issues from an Atlassian account using the Jira REST API.

Set up Atlassian Jira project

You will need an account on Atlassian. Sign up or log in to your Atlassian account. After verifying your email, create your site name and keep this address safe, we will need it later.

Once you’ve created your site, you will be prompted to set up your Jira software. Follow the steps below to complete the setup:

  1. You will see a loading page, wait for your site to be set up.
  2. On the “Help us set up your Jira” page, answer the question prompts and click “Next”.
  3. On the next page, give your project a name and click “Create”.
  4. On the next page you will be asked to connect apps, click “Skip”.
  5. On the “Invite your teammates” page click “Done”.

After completing these steps you will see your project board like the one below:

Create a new issue by clicking the + Create issue button in the “TO DO” column. Give it any name, we are creating this issue so that we can test if our integration is working later on.

To communicate with the Jira REST API, we’ll need our project key and an API token.

Get your project key

To get your project key, click the “Projects” button at the top of your board view, then click “View all projects”.

There you will see a list of your Jira projects. Take note of the key assigned to the project we’ve just created.

Get your access token

To create an access token:

  1. Click on your profile image in the top right of the screen.
  2. Click “Manage account”.
  3. On the next page, click “Security” in the menu on the left.
  4. Click “Create and manage API tokens”.
  5. Click “Create API token”.
  6. Give your token a label and click “Create”.
  7. Finally, when your token has been created, click “Copy” to copy your token.

Keep the token somewhere safe so that we can use it to authenticate our requests to the Jira REST API.

Use Jira REST API to access your Jira issues

Now that we have an access token, we can use it to query the Jira REST API and retrieve all the issues from our project.

In the request.js file, add the code below:


import { createTaskBoard } from './index.js';
 
const serverAddress = 'http://localhost:3000';
const clientAddress = 'http://localhost:8080';
 
async function getTasksFromJira() {
  fetch(`${serverAddress}/getIssues/`, {
    method: 'GET',
    mode: 'cors',
    headers: {
      'Access-Control-Allow-Origin': clientAddress,
      'Content-Type': 'application/json',
    },
  })
    .then((response) => response.json())
    .then((data) => createTaskBoard(data));
}
 
export { getTasksFromJira };

Here we define a function called getTasksFromJira that makes a query to the server that we will create in the next step. The query receives a list of all the issues from our server and then initiates a function called createTaskBoard. This function call will create our TaskBoard with all the data from our Jira project included.

Before we sync our TaskBoard we must set up our local server. In the server.js file, add the code below:


import express from 'express';
import fetch from 'node-fetch';
import cors from 'cors';
 
const atlassianAddress = '<your-atlassian-address-here>' + 'rest/api';
const projectKey = '<your-project-key-here>';
const email = '<your-email-here>';
const token = '<your-api-token-here>';
 
const transitionList = {
  'to do': '11',
  'in progress': '21',
  'done': '31',
};
 
const authHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Accept': 'application/json',
  'Content-Type': 'application/json',
  'Authorization': `Basic ${Buffer.from(
    `${email}:${token}`,
  ).toString('base64')}`,
};
 
const app = express();
 
app.use(cors({
  origin: 'http://localhost:8080',
}));
 
app.use(express.json());
 
app.get('/getIssues', function (req, res) {
  fetch(`${atlassianAddress}/2/search?jql=project=${projectKey}`, {
    method: 'GET',
    headers: authHeaders,
  })
    .then((res) => res.json())
    .then((json) => res.send(json));
});
 
app.listen(3000, function () {
    console.log('Listening on port 3000!');
  });

Here we use ExpressJS to create a get route on /getIssues which will make a request to the Jira REST API and return all of the issues from our Jira project. We also create our server with app.listen which will run our server on port 3000.

Add your own information as follows:

  1. Replace <your-atlassian-address-here> with the site address you created when setting up your Atlassian account. Be sure to end off the address with a forward slash / and prefix the address with a protocol.
  2. Replace <your-project-key-here> with the Jira project key we retrieved earlier.
  3. Replace <your-email-here> with the email address you used to create your Atlassian account.
  4. Replace <your-api-token-here> with the API token we created earlier.

Take note that in this example, we hard-code the access token and personal information for the sake of simplicity. For production environments, it’s more secure to keep sensitive information in environment variables.

Next, install the packages we need to run our server with the following command:

npm install cors express node-fetch

Next we will add our Jira issues to our Bryntum TaskBoard. Replace all the code in the index.js file with the following code:


import { TaskBoard, TaskStore } from '@bryntum/taskboard/taskboard.module.js';
import { getTasksFromJira } from './request.js';
  
getTasksFromJira();
 
function getIssueData(issues) {
  const issueList = [];
  issues = issues.issues;
  for (let i = 0; i < issues.length; i++) {
    const newIssue = {
      jiraId: issues[i].key,
      name: issues[i].fields.summary,
      status: issues[i].fields.status.name.toLowerCase(),
    };
    issueList.push(newIssue);
  }
  return issueList;
}
 
function createTaskBoard(issues) {
  const taskStore = new TaskStore({
    data: getIssueData(issues),
  });
  const taskBoard = new TaskBoard({
    appendTo: document.body,
    columnField: 'status',
    columns: [
      'to do',
      'in progress',
      'done'
    ],
    project: {
      taskStore
    }
  });
}
 
export { createTaskBoard };

Here we create the createTaskBoard function that will create our TaskBoard instance, then we create our issues using the getIssueData function. The getIssueData function takes in the results of the request to Jira and formats the issues to match the Bryntum inline data format.

Now run your newly created server using the following command:

node server.js

If you run npm run dev in a new terminal now, you will see the items from your Jira project reflected in the Bryntum TaskBoard.

Implementing CRUD

Now that our Bryntum TaskBoard has received all the items from our Jira API, we’ll implement the rest of the CRUD functionality by taking advantage of Jira’s REST API.

Create events

In the server.js file, add the following lines above app.listen:


app.post('/addIssue', function (req, res) {
  const transitionType = transitionList[req.body.status];
  const bodyData = {
    'fields': {
      'summary': req.body.summary,
      'project': {
        'key': projectKey,
      },
      'issuetype': {
        'id': '10001',
      },
    },
    'transition': {
      'id': transitionType,
    }
  };
 
  fetch(`${atlassianAddress}/3/issue`, {
    method: 'POST',
    headers: authHeaders,
    body: JSON.stringify(bodyData),
  })
    .then((res) => res.json())
    .then((json) => res.send(json))
    .catch((err) => console.log(err));
});

Here we define the /addIssue post request, this will create an issue in our Jira project using the name and status (to do, in progress, and done). The name is changed through the summary definition and the status is defined through the transition definition.

Update events

In the server.js file, add the following lines above app.listen:


app.put('/updateName', function (req, res) {
  fetch(`${atlassianAddress}/2/issue/${req.body.key}`, {
    method: 'PUT',
    headers: authHeaders,
    body: JSON.stringify({
      'update': {
        'summary': [
          {
            'set': req.body.summary,
          }
        ],
      },
    }),
  })
    .catch((err) => console.log(err));
});
 
app.post('/updateTransition', function (req, res) {
  const transitionType = transitionList[req.body.status];
  fetch(`${atlassianAddress}/2/issue/${req.body.key}/transitions`, {
    method: 'POST',
    headers: authHeaders,
    body: JSON.stringify({
      'transition': {
        'id': transitionType,
      }
    }),
  })
    .catch((err) => console.log(err));
});

The /updateName and /updateTransition routes will handle the requests to change the name and status of our issues.

Delete events

In the server.js file, add the following lines above app.listen:


app.delete('/deleteIssue', function (req, res) {
  fetch(`${atlassianAddress}/3/issue/${req.body.key}`, {
    method: 'DELETE',
    headers: authHeaders,
  })
    .catch((err) => console.log(err));
});

The /deleteIssue route will identify the appropriate issue by its key and delete the issue from our Jira project.

Listening for event data changes in Bryntum TaskBoard

Next, we’ll set the listeners for our Bryntum TaskBoard so that it will know when the user updates the TaskBoard events.

In the index.js file, add the listener property above the data: getIssueData(issues), line:

    listeners: {
      change: function (event) {
        updateJira(event);
      }
    },

Here we set a listener on our Bryntum TaskBoard to listen for any changes to the task board’s data store. This will fire an "add" event whenever a task board item is created, an "update" event when an item is updated, and a "remove" event whenever an item is deleted.

The item retrieved from the change listener also carries event data about the specific TaskBoard item that has been altered. We’ll use the event data to identify which item is being altered and what’s being changed.

Next we’ll create a function called updateJira that will update your Jira project when the appropriate "add""update", or "delete" event is fired.

Add the following code below the getTasksFromJira function in the request.js file:


async function sendRequest(event, address, requestMethod) {
  const requestBody = {
    'key': event.records[0].data.jiraId,
    'status': event.records[0].data.status,
    'summary': event.records[0].data.name,
  };
  await fetch(`${serverAddress}/${address}/`, {
    method: requestMethod,
    mode: 'cors',
    headers: {
      'Access-Control-Allow-Origin': clientAddress,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(requestBody),
  })
    .then((res) => res.json())
    .then((results) => event.records[0].data.jiraId = results.id)
    .then((data) => console.log(data));
}
 
async function updateJira(event) {
  if (event.action === 'update' && 'name' in event.changes) {
    sendRequest(event, 'updateName', 'PUT');
  } else if (event.action === 'update' && 'status' in event.changes) {
    sendRequest(event, 'updateTransition', 'POST');
  } else if (event.action === 'add' && event.records.length === 1) {
    sendRequest(event, 'addIssue', 'POST');
  } else if (event.action === 'remove' && event.records.length === 1) {
    sendRequest(event, 'deleteIssue', 'DELETE');
  }
}

Here we create the updateJira function that is called on all changes to the data store of Bryntum TaskBoard. It then creates a request to our server with the sendRequest function to request the appropriate Jira REST API CRUD functions we defined.

On "update", we check whether the item name or status is being updated. We then make the request to either the /updateName or /updateTransition route. We pass in the event information since we can extract the Bryntum TaskBoard task’s name, status, and ID for the request.


async function updateJira(event) {
  if (event.action === 'update' && 'name' in event.changes) {
    sendRequest(event, 'updateName', 'PUT');
  } else if (event.action === 'update' && 'status' in event.changes) {
    sendRequest(event, 'updateTransition', 'POST');
  }

On "add", we make the request to the /addIssue route.

else if (event.action === 'add' && event.records.length === 1) {
    sendRequest(event, 'addIssue', 'POST');
  } 

On "remove", we make the request to the /deleteIssue route.

else if (event.action === 'remove' && event.records.length === 1) {
    sendRequest(event, 'deleteIssue', 'DELETE');
  }

Finally, change the exports in request.js to the following:

export { getTasksFromJira, updateJira };

And change the imports in index.js to the following:

import { TaskBoard, TaskStore } from '@bryntum/taskboard/taskboard.module.js';
import { getTasksFromJira, updateJira } from './request.js';

Now run your server to create, update, delete, and edit an item in the Bryntum TaskBoard. You’ll see the changes reflected in your Jira project.

Next steps

This tutorial gives you a starting point for creating a Bryntum TaskBoard using vanilla JavaScript and syncing it with Atlassian’s Jira software. There are many ways you can improve your Bryntum TaskBoard, for example, you can add features such as task filters. Take a look at our demos page to see demos of the available features.

Bryntum

Bryntum Taskboard