How to build a dynamic form in MacroConfig panel?

Hi @ThibautFAURE ,
I had a similar problem. I wanted to search for specific attachments on the current page or a specific page.
This source code works for my use case.

import ForgeUI, {
    MacroConfig,
    Option,
    render,
    Select,
    TextField,
    useConfig,
    useProductContext,
    useState
} from '@forge/ui';
import api, { route } from "@forge/api";



const fetchAttachments = async (targetPageId) => {
    const { contentId } = useProductContext();
    let pageId = contentId;
     if (targetPageId && targetPageId.length > 0) {
         pageId = targetPageId;
     }
    const response = await api.asUser().requestConfluence(route`/rest/api/content/${pageId}/child/attachment?mediaType=application/dataforms`);
    let theJson = await response.json();
    return theJson.results ? theJson.results : [];
};

const getNameFromCommentJson = (comment) => {
    try {
        return JSON.parse(comment).name;
    } catch(e) {
        return comment;
    }
}

const Config = () => {
    let targetPageId = undefined;
    try {
        targetPageId = useConfig().targetPageId;
    } catch (e) {
    }
    const [ attachments ] = useState(fetchAttachments(targetPageId));
    return (
        <MacroConfig>
            <TextField label="Page Id (optional)" description="The current page is used if nothing has been entered here." name="targetPageId"  />
            <Select label="Data Form" name="dataformAttachment">
                {attachments.map(attachment => {
                    return (
                        <Option
                            label={`${getNameFromCommentJson(attachment.extensions.comment)} (${attachment.title})`}
                            value={attachment.id} />
                    )
                })}
            </Select>
        </MacroConfig>
    );
};
export const config = render(<Config />);

With this modification it should work (not tested) for your source code.

import ForgeUI, { useConfig, useEffect, render, Fragment, Text, Macro, Form, TextField, MacroConfig, Select, Option, useProductContext, useState } from '@forge/ui';
import api from "@forge/api";


// Get list of Jira Project
const fetchProjects = async () => {
  const response = await api.asUser().requestJira("/rest/api/3/project");
  console.log("Jira projet list - STATUS HTTP: "+ response.status);

  if (!response.ok) {
    return "Error to get Jira projet list" + response;
  }

  return await response.json();
};

// Get list of Jira issue type depend of Jira Project
const fetchIssueTypes = async (projectId: string) => {
  let toUseProjectId = "10001";
  if (projectId && projectId.length > 0) {
    toUseProjectId = projectId
  }
  const response = await api.asUser().requestJira("/rest/api/3/project/"+toUseProjectId);
  console.log("Jira issue type - projectId: "+ toUseProjectId);
  console.log("Jira issue type - STATUS HTTP: "+ response.status);

  if (!response.ok) {
    return "Error to get Jira issue type list" + response;
  }

  return await response.json();
};


const App = () => {
  // Retrieve the configuration
  const config = useConfig();

  // Use the configuration values
  return (
    <Fragment>
      <Text>Hello world!</Text>
    </Fragment>
  );
};
export const run = render(
  <Macro app={<App />} />
);


// Function that defines the configuration UI
const Config = () => {
    let projectKey = undefined;
    try {
        projectKey = useConfig().projectKey;
    } catch (e) {
    }
  const [projects] = useState(fetchProjects);
  const [issueTypes] = useState(fetchIssueTypes(projectKey)); 

  return (
    <MacroConfig>
      <Select label="Project" name="projectKey">
        {projects.map(project => {
          return (
            <Option label={`${project.name} (${project.key})`} value={project.Id} />
          )
        })
      }
      </Select>
      <Select label="Issue Type" name="issueType">
        {issueTypes.issueTypes.map(issueType => {
          return (
            <Option label={`${issueType.name}`} value={issueType.Id} />
          )
        })}
      </Select>
    </MacroConfig>
  );
};

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