MacroConfig: useConfig() is always undefined

Hi guys,

I’m struggling displaying values from my MacroConfig in Confluence.
With the help of the hello-world from forge and this article I am able to get two fields to configure a macro.

I use useConfig() to receive those values but never get a result. Why is this?
src/index.js:

import ForgeUI, {
  render,
  Macro,
  MacroConfig,
  Text,
  TextField,
  useConfig,
} from "@forge/ui";
import Resolver from '@forge/resolver';

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

const configuration = useConfig() || defaultConfig;

const resolver = new Resolver();

resolver.define("getText", ({ payload, context }) => {
    console.log("useConfig():",useConfig())
    console.log("configuration:",configuration)
    return { example: `Hello, ${payload.name}!`, config: configuration };
});

export const handler = resolver.getDefinitions();

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

export const config = render(<Config />);

manifest.yml:

modules:
  macro:
    - key: my-app
      resource: main
      resolver:
        function: resolver
      title: My App
      description: Inserts my-app.
      config:
        function: config-function-key
  function:
    - key: resolver
      handler: index.handler
    - key: config-function-key
      handler: index.config
resources:
  - key: main
    path: static/my-app/build
app:
  id: ari:cloud:ecosystem::app/3e1df895-daa1-48dd-ad62-1f934debb539
permissions:
  scopes:
    - read:confluence-content.summary
    - read:confluence-props
    - write:confluence-props
  content:
    styles:
      - 'unsafe-inline'
    scripts:
      - 'unsafe-inline'
      - 'unsafe-hashes'
  external:
    styles:
      - '*'
    scripts:
      - '*'
    images:
      - '*'
    fonts:
      - '*'
    fetch:
      client:
        - '*'
      backend:
        - '*'

static/my-app/src/index.js:

import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { invoke } from "@forge/bridge";

import '@atlaskit/css-reset';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

static/my-app/src/App.js:

import React, { useEffect, useState } from 'react';
import { invoke } from '@forge/bridge';

function App() {
    const [data, setData] = useState(null);

    useEffect(() => {
        invoke("getText", { name: "World" }).then(setData);
    }, []);

    if (data != null) {
        console.log(`data:`, JSON.stringify(data, null, 2));
    }

    return (
        <div>
            {data != undefined ? `Macro data: ${data.config.name} ${data.config.age}` : 'Loading...'}
        </div>
    );
}

export default App;

The result I get is always the same. Log gives me:

Serving file index.html for resource main

invocation: 3480b459f461686b index.handler
INFO    15:05:36.465  3480b459f461686b  useConfig(): undefined
INFO    15:05:36.473  3480b459f461686b  configuration: { name: 'Unnamed Pet', age: '0' }

And in the browser my #root (index.html is unchanged) is filled with the string: “Macro data: Unnamed Pet 0”

Steps when I do changes:

  • ‘npm run build’ in static/my-app
  • forge deploy in the root of my app

What am I doing wrong? Missing dependencies?
I appreciate any help, thank you very much!

Hi @thomas.egger,
Thanks you for reaching out. in custom UI apps config will get pass along with the context. Please try below in your src/index.js instead of useConfig.

resolver.define("getText", ({ payload, context }) => {
   const configuration = context.extension.config || defaultConfig;
   ...
});

Thank you very much!