This tutorial will walk you through creating a more complex Forge app for Jira using UI Kit.
The Jira Weather Gadget app is designed to show you how to create an app that allows a user to enter their location, and use that information to get data from an external API and display it.
Approximate time needed: 30-40 minutes
Suggested Skills: Basic understanding of Javascript, React is recommended.
First, you'll create your Forge UI kit app using the Jira dashboard gadget template, you will customise the Configuration screen and display the configuration data in the app.
Then, you'll modify the app to call the OpenWeather API, and display the weather in your app. You will also learn how to store and access environment variables in Forge.
Finally you'll further customise the app to use UI Kit layout elements to improve the apps appearance.
Along the way, you'll find extra tips, links and resources that will allow you to learn more about what was covered in each section, and become familiar with how resources are laid out in the Forge documentation.
We recommend completing Forge Quest in order. If you haven't completed the first quest, it is recommended you complete that before starting this tutorial.
In this tutorial, we'll be using OpenWeatherMap API to get current weather conditions to display in our app. Sign up for a free account and generate your API key as you'll need them in this tutorial. You won't need a paid subscription for this tutorial.
Create an app based on the Jira dashboard gadget template.
Create your app by running:
1 2forge create
Enter a name for your app (up to 50 characters). For example weather-gadget.
Select the UI Kit category.
Select Jira from the list of products.
Select the jira-dashboard-gadget template.
Change to the app subdirectory to see the app files:
1 2cd weather-gadget
The app we'll create will create a Jira Dashboard Gadget, which can be added to the Dashboards page in Jira Work Management, Jira Software and Jira Service Management.
1 2forge deploy
1 2forge install
jira
using the arrow keys and press the enter key.Once the install complete message appears, your app is installed and ready to use on the site specified. You can delete your app from the site by running the forge uninstall
command.
Now that your app is installed, it's time to see it in action in your Jira site.
In this section, you'll make some changes to the src/frontend/index.jsx
to modify the Edit view of the app to prompt the user to enter their Country and City, which you will need later to get the local weather information.
Start your tunnel by running
1 2forge tunnel
Navigate to the src/frontend
directory.
Open the index.jsx
file. The default content of the file is shown below:
1 2import React, {useEffect, useState} from "react"; import ForgeReconciler, { Text, useProductContext, Textfield, Form, Button, FormSection, FormFooter, Label, RequiredAsterisk, useForm, } from "@forge/react"; import { invoke, view } from "@forge/bridge"; const FIELD_NAME = "field-name"; export const Edit = () => { const { handleSubmit, register, getFieldId } = useForm(); const configureGadget = (data) => { view.submit(data); }; return ( <Form onSubmit={handleSubmit(configureGadget)}> <FormSection> <Label labelFor={getFieldId(FIELD_NAME)}> Value <RequiredAsterisk /> </Label> <Textfield {...register(FIELD_NAME, { required: true })} /> </FormSection> <FormFooter> <Button appearance="primary" type="submit"> Submit </Button> </FormFooter> </Form> ); }; const View = () => { const [data, setData] = useState(null); const context = useProductContext(); useEffect(() => { invoke('getText', { example: 'my-invoke-variable' }).then(setData); }, []); if (!context) { return "Loading..."; } const { extension: { gadgetConfiguration }, } = context; return ( <> <Text>Value: {gadgetConfiguration[FIELD_NAME]}</Text> <Text>{data ? data : 'Loading...'}</Text> </> ); }; const App = () => { const context = useProductContext(); if (!context) { return "Loading..."; } return context.extension.entryPoint === "edit" ? <Edit /> : <View />; }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
The Edit function returns a form with a textfield, label and submit button. Modify the textfield and label so they ask the user to enter their City,
1 2<Label> City <RequiredAsterisk /> </Label> <Textfield {...register("city", { required: true })} />
To learn more about UI kit Forms, you can consult the reference docs at https://developer.atlassian.com/platform/forge/ui-kit-2/heading/
In the Edit function, below the City field, create a new textfield and label for the Country,
1 2<Label> Country <RequiredAsterisk /> </Label> <Textfield {...register("country", { required: true })} />
Modify the App return statement to display the city and country entered by the user,
1 2return ( <> <Text>City: {gadgetConfiguration["city"] ? gadgetConfiguration["city"] : "Edit me"}</Text> <Text>Country: {gadgetConfiguration["country"] ? gadgetConfiguration["country"] : "Edit me"}</Text> </> );
Save the changes you made to index.jsx
.
Once the tunnel has completed its reload, refresh your Jira dashboard to see the changes.
Click on the ...
and select Configure
to view the edit screen and enter your city and country.
The ...
option allowing you to configure your gadget will only appear when the dashboard is in Edit mode.
Once you're happy with your changes, close the tunnel using Control + c and deploy your changes,
1 2forge deploy
Your src/frontend/index.jsx
should look like this:
1 2import React, {useEffect, useState} from "react"; import ForgeReconciler, { Text, useProductContext, Textfield, Form, Button, FormSection, FormFooter, Label, RequiredAsterisk, useForm, } from "@forge/react"; import { invoke, view } from "@forge/bridge"; export const Edit = () => { const { handleSubmit, register } = useForm(); const configureGadget = (data) => { view.submit(data); }; return ( <Form onSubmit={handleSubmit(configureGadget)}> <FormSection> <Label> City <RequiredAsterisk /> </Label> <Textfield {...register("city", { required: true })} /> <Label> Country <RequiredAsterisk /> </Label> <Textfield {...register("country", { required: true })} /> </FormSection> <FormFooter> <Button appearance="primary" type="submit"> Submit </Button> </FormFooter> </Form> ); }; const View = () => { const [data, setData] = useState(null); const context = useProductContext(); useEffect(() => { invoke('getText', { example: 'my-invoke-variable' }).then(setData); }, []); if (!context) { return "Loading..."; } const { extension: { gadgetConfiguration }, } = context; return ( <> <Text>City: {gadgetConfiguration["city"] ? gadgetConfiguration["city"] : "Edit me"}</Text> <Text>Country: {gadgetConfiguration["country"] ? gadgetConfiguration["country"] : "Edit me"}</Text> </> ); }; const App = () => { const context = useProductContext(); if (!context) { return "This is never displayed..."; } return context.extension.entryPoint === "edit" ? <Edit /> : <View />; }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
In the next step you will modify the app to call the OpenWeather API, and display the weather in your app. You will also learn how to store and access environment variables in Forge.
Rate this page: