How to create custom content for SpaceCustomContentListView?

Hello - could you please explain or refer me to docs on how to create and register a custom content in my Forge App and how to register it to be rendered under SpaceCustomContentListView? Thanks a lot!

Hi @AsmaaHadir, thanks for reaching out.

Please refer to this page, which explains how to register custom content with Forge. Let us know if you have follow-up questions.

Hi @OleksandrBeztsinnyi - thank you for your reply. I had actually referred to the same page to understand how to create my custom content for my app but I still have a couple of questions. For instance, I have written the following code based on confluence’s REST API’s to test the creation a custom content ‘keyword’ but I keep getting errors regarding the values of the bodyData keys indicating that spaceId for instance is of type Long:


import api, { route } from "@forge/api";

const customContent = async () => {

  const {spaceKey, localId, environmentType} = useProductContext();
  const type = `forge:${localId}:${environmentType}:keyword`;
  var bodyData = `{
    "type": "<string>",
    "status": "current",
    "spaceId": "<string>",
    "pageId": "<string>",
    "blogPostId": "<string>",
    "customContentId": "<string>",
    "title": "<string>",
    "body": {
      "representation": "storage",
      "value": "<string>"
    }
  }`;
  
  const response = await api.asUser().requestConfluence(route`/wiki/api/v2/custom-content`, {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: bodyData
  });

Also, How do I practically register/save the custom content that I have Posted? or the API call all what I need to perform? for context, my manifest.yml looks like this:

modules:
  confluence:spacePage:
    - key: keywise-test-space-page-hello-world
      function: main
      title: KeyWise-test for Asmaa
      route: hello-world
  function:
    - key: main
      handler: index.run
app:
  id: ari:cloud:ecosystem::app/134c6c41-0af6-4788-adc3-bd01fd2fc3ec

permissions:
  scopes:
    - read:space:confluence
    - read:confluence-content.summary
    - read:content-details:confluence
    - read:page:confluence
    - write:custom-content:confluence

Thanks a lot in advance :slight_smile:

Hey @AsmaaHadir ,

thanks for more details.
Do you register keyword custom content under the space container? (I don’t see this from your manifest example)

What do you put as a spaceId in bodyData?

Also, How do I practically register/save the custom content that I have Posted? or the API call all what I need to perform? for context

That’s right. The only way to create custom content is with REST API. Once a custom content module is registered, custom content can be created from any other registered module.

Hi @OleksandrBeztsinnyi - What do I need to modify about my manifest.yml to register the keyword custom content?

I have created a helper function to retrieve the current space ID as the following:


export const getSpaceIdByKey = async (spaceKey) => {

  
    const response = await api.asUser().requestConfluence(route`/wiki/api/v2/spaces?${spaceKey}`, {
      headers: {
        'Accept': 'application/json'
      }
    });
  
    
    const data_response = await response.json();
  
    
    // Iterate through the results to find the space with the matching key
    for (const space of data_response.results) {
      if (space.key === spaceKey) {
        return space.id; // Return the ID of the matching space
      }
    }
  
    // If no matching space is found, you can return null or handle the error accordingly
    console.log("space key not found")
    return null; 
  }

and I insert the number that I retrieve from it into the spaceId field. Also, How do I add custom fields so that I can render them in the SpaceCutomContentViewList ? Thank you so much for the help.

Hey @AsmaaHadir,

you must register a module for custom content in your manifest. Something like

modules:
  confluence:customContent:
    - key: keyword
      title: Keywords
      description: Custom content for keywords
      bodyType: raw
      supportedContainerTypes:
        - space
      function: keywordView
  confluence:spacePage:
     ....

having this module gives you the ability to use Custom Content REST API.

The way you get spaceId should work.

How do I add custom fields so that I can render them in the SpaceCutomContentViewList ?

SpaceCustomContentListView is a simple predefined component. It displays only icon, title, contributors, and last modified date. If you want to display your own custom fields in the list the SpaceCustomContentListView component can’t be used. You should create your own component for this purpose.

Thank you so much @OleksandrBeztsinnyi for the simplified explanation.
Regarding this point:

Even though I can’t display additional properties under the SpaceCustomContentListView UI, I can still add my own fields to my keyword custom content type in its bodyData and use custom UI to display them, right? Otherwise if I choose to use SpaceCustomContentListView the user would need to click on a custom content key to render the page with additional properties?

One more question: regarding the function field for my CustomContent module in manifest.yml, it is basically a function that I define which makes a REST API call and retrieves a custom content for me, or is it the main function in App() which displays the customContent in the UI? for example, based on the sample manifest.yml file that you have replied with, I could define a keywordView function which returns a keyword custom content with API calls and use it inside my App() main function?

Hey @OleksandrBeztsinnyi - sorry for the multiple questions but I got a bit confused reading the documentation. What does the extractAppId refer to when defining the type field for the custom content type below?

    // extractAppId implementation omitted
    const type = `forge:${extractAppId(localId)}:${environmentType}:note`;

I can still add my own fields to my keyword custom content type in its bodyData and use custom UI to display them, right?

Right.

Otherwise if I choose to use SpaceCustomContentListView the user would need to click on a custom content key to render the page with additional properties?

Correct. SpaceCustomContentListView displays a list of custom content. However, actual custom content will be rendered when the user clicks on the title.

regarding the function field for my CustomContent module

this function defines the UI that will be rendered for specific custom content (when the user clicks on the title of one of the list items of SpaceCustomContentListView). This function should fetch the body (or other params) of custom content before being displayed.

What does the extractAppId refer to when defining the type field for the custom content type below?

As it was mentioned in the documentation, the type for registered Forge custom content will have this format
forge:[APP_ID]:[ENVIRONMENT_ID]:[MODULE_KEY]

For example:

forge:b44c55b2-251f-45e3-8ea4-b56762f82e8a:f7522737-117c-46e7-a7ca-03a73c99afcf:keyword

  • APP_ID: The identifier for your Forge app. To get the app ID, use the useProductContext hook. The app ID is a part of the localId attribute.

To get APP_ID from localId you should parse it, that’s what extractAppId does.

Hope this helps

Thank you for the clear answers @OleksandrBeztsinnyi