Last updated Feb 23, 2024

This guide only applies to UI Kit 2 (Preview) apps. If your app is using UI Kit 1 or Custom UI, please follow this guide.

Add configuration to a macro with UI Kit 2

Configuration allows you to customize what the macro displays by adjusting settings in a form. To access these settings, you need to go into the edit mode for the macro, as demonstrated below. This gives you the ability to customize the macro's output according to your preferences.

Example of configuring a Forge macro

Before you begin

Make sure you have the following:

  • Confluence macro created using UI Kit 2 (Preview)
  • The latest version of Forge CLI. To update your CLI version, run npm install -g @forge/cli@latest on the command line.
  • The latest version of UI Kit 2 (Preview). To update your version, navigate to the app's top-level directory, and run npm install @forge/react@latest --save on the command line.

Add configuration to the Confluence macro module

In this tutorial, we will add fun facts about pets which are passed through configuration we create. We recommend you to change the values as listed in the below manifest.yml file.

To add configuration to the Confluence macro module:

  1. In the app’s top-level directory, open the manifest.yml file.
  2. Add the config property with the value set to true.

After doing this, your manifest.yml should look like the following, with your own values for each of the properties.

1
2
modules:
  macro:
    - key: pet-facts
      resource: main
      render: native
      resolver:
        function: resolver
      title: Pet
      config: true
  function:
    - key: resolver
      handler: index.handler
resources:
  - key: main
    path: src/frontend/index.jsx
app:
  id: "<your app id>"

Create the configuration

We recommend clearing the src/frontend/index.jsx file and replacing it with the provided code for error free results.

You can create a new function component that will return the configuration(Config) components. The config components must be selected from the following list:

Configuration is stored in key-value pairs corresponding to each form component.

  1. In your src/frontend/index.jsx file, create a function component that constructs the configuration of the UI Kit 2 components you're using

    1
    2
    import React from 'react';
    import { TextField } from '@forge/react';
    
    const Config = () => {
      return (
        <>
          <TextField name="age" label="Pet age" />
        </>
      );
    };
    
  2. At the bottom of the src/frontend/index.jsx file, call the addConfig method on ForgeReconciler with your config element. Ensure you have ForgeReconciler imported at the top.

    1
    2
    import ForgeReconciler, { TextField } from "@forge/react"
    
    ForgeReconciler.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );
    
    ForgeReconciler.addConfig(<Config />);
    

Use config to store general data, but not sensitive information. The config data is stored in plaintext, so other users and apps can access and modify the values.

Use the configuration

You access the config for a macro in your app code with the getContext method. When this method resolves, it returns the product context, which will include the key-value pairs set in the config. The key is the name property on the form component in configuration, and the value is what the user enters.

In your src/frontend/index.jsx file:

  1. Import useState and useEffect.
1
2
import React, { useState, useEffect } from 'react'; 
// useState: Adds and updates local state to a component. 
// useEffect: Executes a specific function whenever any value in its dependency array (the second argument of the hook) changes.
  1. Import view from @forge/bridge in your app code.
    1
    2
    import { view } from '@forge/bridge';
    
  2. Add Text and TextField components.
    1
    2
    import ForgeReconciler, { Text, TextField } from '@forge/react';
    
  3. Create a component called App and call the getContext method in the useEffect.
    1
    2
    const Config = () => {
    ...
    };
    
    const App = () => {
      const [context, setContext] = useState(undefined);
    
      useEffect(() => {
        view.getContext().then(setContext);
      }, []);
    
      return (
        <>
          <Text>Hello World</Text>
        </>
      );
    };
    
  4. Access the configuration data by key within the App component. Add the second text component with age to the return statement.
    1
    2
    const App = () => {
    
      ...
    
      const config = context?.extension.config;
      const age = config?.age;
    
      return (
        <>
          <Text>Hello World</Text>
          <Text>
            {age || 'Fetching config...'}
          </Text>
        </>
      );
    }
    

The index.jsx file should look like this:

1
2
    import React, { useState, useEffect } from 'react';
    import ForgeReconciler, { Text, TextField } from '@forge/react';
    import { view } from '@forge/bridge';

    const Config = () => {
      return (
        <>
          <TextField name="age" label="Pet age" />
        </>
      );
    };
    const App = () => {
      const [context, setContext] = useState(undefined);

      useEffect(() => {
        view.getContext().then(setContext);
      }, []);
      const config = context?.extension.config;
      const age = config?.age;

      return (
        <>
          <Text>Hello World</Text>
          <Text>
            {age || 'Fetching config...'}
          </Text>
        </>
      );
    };
    ForgeReconciler.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );

    ForgeReconciler.addConfig(<Config />)

We recommend you add sensible defaults for each of your configuration values.

If it's more sensible for the macro to not have default configuration values, we recommend you display a section message with the appropriate instructions, as shown below:

1
2
import ForgeReconciler, { Text, TextField, SectionMessage } from '@forge/react'; 
//Add SectionMessage to the import statement

<SectionMessage title="You need to configure this macro" appearance="warning">
  <Text>
    While editing the page, select the macro, and click on the pencil icon
    to display configuration options.
  </Text>
</SectionMessage>

You can also add a state to only display the section message if the macro has not already been configured, otherwise it will always show on the macro.

Add default pet configuration

In this example, by default, the macro displays Unnamed Pet is 0 years old.

Create a default configuration for the pet's name and age, and then add defaultConfig variable to const config = context?.extension.config

In your src/frontend/index.jsx file outside the Config and App components, add:

1
2
const defaultConfig = {
  name: 'Unnamed Pet',
  age: '0'
};

Then replace the const config inside the App component with the following:

1
2
 const config = context?.extension.config || defaultConfig;

Add dynamic input values for the pet's name and age.

Now that we have created configurations (name and age) for your macro, we can now enhance this feature to include dynamic input for the pet's name and age.

For example, if a user submits the name Fluffy and age 2, the macro displays Fluffy is 2 years old.

In your index.jsx file:

Add function that defines the config UI for the pet's name and age

1
2
const Config = () => {
  return (
    <>
      <TextField name="name" label="Pet name" defaultValue={defaultConfig.name} />
      <TextField name="age" label="Pet age" defaultValue={defaultConfig.age} />
    </>
  );
};

Display the pet's name and age using the configuration values

In the return statement of the App component:

Replace

1
2
  <Text>Hello World</Text>
  <Text>
    {age || 'Fetching config...'}
  </Text>

with

1
2
  return (
    <Text>{config.name} is {config.age} years old.</Text>
  );

Your main file containing the application's root component (here index.jsx) should look like this:

1
2
import React, { useEffect, useState } from 'react';
import ForgeReconciler, { TextField, Text, SectionMessage } from '@forge/react';
import { view } from '@forge/bridge'

const defaultConfig = {
  name: 'Unnamed Pet',
  age: '0'
};

// Function that defines the configuration UI for the pet's name and age
const Config = () => {
  return (
    <>
      <TextField name="name" label="Pet name" defaultValue={defaultConfig.name} />
      <TextField name="age" label="Pet age" defaultValue={defaultConfig.age} />
    </>
  );
};

const App = () => {
  const [context, setContext] = useState(undefined);
  // Retrieve the context
  useEffect(() => {
    view.getContext().then(setContext);
  }, []);
  
  const config = context?.extension.config || defaultConfig;
  // Displaying the pet's name and age using the configuration values. SectionMessage component is optional.
  return (
    <>
      <Text>{config.name} is {config.age} years old.</Text>
      <SectionMessage title="You need to configure this macro" appearance="warning"> 
        <Text>
          While editing the page, select the macro, and click on the pencil icon
          to display configuration options.
        </Text>
      </SectionMessage>
    </>
  );
};

// Adding the Config function to the ForgeReconciler to allow for configuration changes
ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

ForgeReconciler.addConfig(<Config />);

Install your app

If you haven't done so already, make sure you have installed the latest version of UI Kit 2 before you begin deploying your app. Navigate to the top-level directory of the app and run npm install @forge/react@latest --save on the command line.

Build, deploy, and install the app to see it in your Confluence site.

To use your app, it must be installed onto an Atlassian site. The forge deploy command builds, compiles, and deploys your code; it'll also report any compilation errors. The forge install command then installs the deployed app onto an Atlassian site with the required API access.

You must run the forge deploy command before forge install because an installation links your deployed app to an Atlassian site.

  1. Navigate to the app's top-level directory and deploy your app by running:

    1
    2
    forge deploy
    
  2. Install your app by running:

    1
    2
    forge install
    
  3. Select your Atlassian product using the arrow keys and press the enter key.

  4. 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.

View your app

  1. Edit a Confluence page in your development site.
  2. Select Insert icon from the toolbar from the toolbar.
  3. Find the macro by name and select it. The app is displayed on the page.
  4. Click the pencil icon to open the app's config panel on the right side of the page.
  5. Type the Pet age, Pet name, and then close the configuration page. The config values are saved automatically

You should now see the config values displayed within the app.

Rate this page: