This tutorial describes how to create a Forge app that imports third-party data into Assets. This app allows integrations with third parties by pulling data from external sources during an import. It also contains the triggers that are activated on the deletion, starting, and stopping of an import.
The final app looks like the following:
This tutorial assumes you're already familiar with the basics of Forge development. If this is your first time using Forge, see Getting started first.
To complete this tutorial, you need the following:
npm install -g @forge/cli@latest
on the command line.npm install @forge/react@latest --save
on the command line.An Atlassian cloud developer site lets you install and test your app on Confluence and Jira products set up for you. If you don't have one yet, set it up now:
You can install your app to multiple Atlassian sites. However, app data won't be shared between separate Atlassian sites, products, or Forge environments.
The limits on the numbers of users you can create are as follows:
The Atlassian Marketplace doesn't currently support cross-product apps. If your app supports multiple products, you can publish two separate listings on the Marketplace, but your app won't be able to make API calls across different products and instances/installations.
This functionality of Assets is only available for Jira Service Management Cloud, PREMIUM and ENTERPRISE plans.
The app allows integrations with third parties to allow data from external sources be imported into Assets via a Forge app.
1 2forge create
In the app's top-level directory, open the manifest.yml
file. You will see
the jiraServiceManagement:assetsImportType
and function
modules in
the manifest. The jiraServiceManagement:assetsImportType
module adds entries to the Assets create import menu,
with the value of title
and icon of icon
. The function
module contains logic that triggers off the certain
actions.
Replace the key
, description
, title
& icon
entry under jiraServiceManagement:assetsImportType
with your
values.
1 2jiraServiceManagement:assetsImportType: - key: '<your-module-key>' description: '<your-app-description>' title: '<your-import-type-name>' icon: '<your-icon-url>'
Build, deploy, and install the app to see it in your Jira Service Management site.
Navigate to the app's top-level directory and deploy your app by running:
1 2forge deploy
Install your app by running:
1 2forge install
Select your Atlassian product using the arrow keys and press the enter key.
Enter the URL for your development site. For example, example.atlassian.net. View a list of your active sites at Atlassian administration.
Once the successful installation message appears, your app is installed and ready
to use on the specified site.
You can always delete your app from the site by running the forge uninstall
command.
Running the forge install
command only installs your app onto the selected product.
To install onto multiple products, repeat these steps again, selecting another product each time.
Note that the Atlassian Marketplace
does not support cross-product apps yet.
You must run forge deploy
before running forge install
in any of the Forge environments.
With the app installed, it's time to see the entry in the create import menu.
Navigate to your Jira Service Management site, then click on Assets on the top tab.
Schema configuration
at top left.Import
tab.Create Import
button to open the create import menuYou'll see the Hello World! entry from the app with the Atlassian Logo. Follow the prompts to create your import configuration.
Add UI Kit components that render when a user configures the import. This front-end is displayed in the Configure
app modal available from an import configuration. The configuration modal is configured in src/index.jsx
.
Start tunneling to view your local changes by running:
1 2forge tunnel
Open the src/frontend/index.jsx
file.
Modify to the contents of the file with this or place components you desire
inside App
> AssetsAppImportTypeConfiguration
.
To see your changes, navigate to your Assets schema configuration, edit the import configuration associated with your app, and select Configure app.
A modal dialog displays with:
1 2Hello World!, ImportId = {your-import-id}, WorkspaceId = {your-workspace-id}
In the code from this step:
extensionContext
contains importId
and workspaceId
AssetsAppImportTypeConfiguration
is the component being rendered, make sure you place all your components inside itrun
constant provides the mechanism that renders the app.onSubmit
will be run when the Save configuration
button is clicked.Navigate to src/resolvers/index.jsx
. These are pieces of code you can implement which will be call executed the import flow.
onDeleteImport - Triggers on a deletion of an import structure
1 2const onDeleteImport = async (context) => { console.log("import with id ", context.importId + " got deleted"); return { result: "on delete import", }; };
startImport - Triggers on the start of an import
1 2const startImport = async (context) => { console.log("import with id ", context.importId + " got started"); return { result: "start import", }; };
stopImport - Triggers on the cancellation of an import
1 2const stopImport = async (context) => { console.log("import with id ", context.importId + " got stopped"); return { result: "stop import", }; };
importStatus - Triggers to display the status of the import on the Imports UI
1 2const importStatus = async (context) => { console.log("import with id ", context.importId + " sending import status"); return { status: "NOT_CONFIGURED" }; };
There are two status enums that can be returned.
status: "NOT_CONFIGURED"
will return the NOT CONFIGURED
status as the first image shown above.
status: "READY"
will return with the Import data
button active as the second image shown above.
The imports will be powered by the Imports REST API through its
infrastructure.
However instead of calling GET https://api.atlassian.com/jsm/assets/v1/imports/info
to fetch the initial links to
start the import process you will have to manually generate them.
The three links mentioned in the Imports REST API
in Step 3
can be found here where:
1 2{ "links": { "getStatus": "https://api.atlassian.com/jsm/assets/workspace/{workspaceId}/v1/importsource/{importId}/configstatus", "start": "https://api.atlassian.com/jsm/assets/workspace/{workspaceId}/v1/importsource/{importId}/executions", "mapping": "https://api.atlassian.com/jsm/assets/workspace/{workspaceId}/v1/importsource/{importId}/mapping" } }
With Forge, you do not need to use a container token to call these endpoints, you can use asUser()
or asApp()
requests.
asUser()
will perform the request on behalf of the userasApp()
will perform the request with the permissions of the appMore information about this responsibility model can be
found here. Some examples of
using asUser()
and asApp()
are provided below.
1 2const asUserRequest = await api .asUser() .requestJira( route`/jsm/assets/workspace/${context.workspaceId}/v1/importsource/${context.importId}/executions`, { method: "POST", } );
1 2const asAppRequest = await api .asApp() .requestJira( route`/jsm/assets/workspace/${context.workspaceId}/v1/importsource/${context.importId}/executions`, { method: "POST", } );
The Import data
button in the Imports UI will not be able to be interacted with until you submit a schema and mapping
to the "mapping" endpoint above.
So submit a schema and mapping during the startImport
extension callback or in the Configure App
Modal UI.
With the schema and mapping submitted, the next step would be to implement the startImport
extension point that will
run when Import data
button is clicked.
This code should fetch data from a third party source and push to the Import Asset APIs.
When this is all done you can set your status
to Ready
with the importStatus
extension point, causing
the Import data
button to be active, as shown below.
1 2const importStatus = async (context) => { console.log("import with id ", context.importId + " sending import status"); return { status: "READY" }; };
We recommend following the guide here to be able to import data into Assets.
We have included an example of how to use Forge's Async Events API to import 3rd party data into Assets by setting up a controller and worker queue for data ingestion.
From the diagram above:
The Start Trigger
is represented below with a code snippet in the template from src/resolvers/index.jsx
1 2// Call Assets API here to mark import as started // Push event onto controller queue to start data ingestion process const id = await controllerQueue.push({eventContext: {importConfigurationId: context.importId}}); console.log(`Pushed queueControllerEvent with id ${id}`);
The Controller Queue
is represented below with a code snippet in the template from src/resolvers/controller-resolver.js
1 2const handleControllerEvent = async (eventContext) => { // Push initial work item to worker queue here // e.g. await workerQueue.push({ eventContext: workItem }); // Once the initial work item is pushed to the worker queue, // keep pushing events to the controller queue with a delay until the work items are all complete // e.g. await controllerQueue.push({ eventContext: workItem }); // Once work items are all complete call the Assets API to signal the completion of data submission };
The Generic Worker Queue
is represented below with a code snippet in the template from src/resolvers/worker-resolver.js
1 2const handleWork = async (eventContext) => { // Fetch data from external system here // Update work items according to how much data is left to be fetched // And push to worker queue again if there is more data to be fetched // eg. await workerQueue.push({ eventContext: updatedWorkItem }); };
After confirming the app works locally, deploy the app so that it continues to work when you close the tunnel.
1 2forge deploy
That’s it. You've built an app that retrieves the contents of a page, counts the number of macros, then displays the result in a modal dialog.
Check out an example app, continue to one of the other tutorials, or read through the reference pages to learn more.
Rate this page: