Macro Bodies in Forge

Many of our existing server and cloud apps are confluence macros that perform their work against user supplied content nested within the body of the macro. The Forge documentation shows how to configure macros through parameters but I don’t find support for macro body content. Is this available and if not when might we expect to see that support in Forge?

Jeff

9 Likes

Hey Jeff—I’ve reached out to the team responsible for this, but my understanding is that there are currently no concrete plans to do nested body macros.

1 Like

Hey Jeff!
We currently don’t support nested body macro, but we are actively looking at ways we might be able to support server-like behaviour inside of Forge Macros right now. I unfortunately don’t have a concrete timeline for when that will land, or what that experience might look like.

1 Like

Hi shraj, any update on this one? I’m trying to create a new Forge Macro, but also need to be able to parse the body of the macro…

Thanks,
Remo

1 Like

@remo.siegwart

Hey! I’m not entirely sure what you mean about the body of the macro in this case - from my understanding, the Forge Macros today only contain content that the app themselves have written, and therefore the app should have access to its own content. We don’t currently offer the ability to nest macros within each other like we see in Server/P2 (where there is a separate bodied component to the app), nor do we have concrete plans to do so in the near future.

It will be interesting to see what happens here, especially with regard to (hopefully) being able to eventually migrate existing Connect macros that have plain text bodies to Forge.

We have customers with pages that still use the old TinyMCE editor (which supported pasting/typing content in the macro body insitu on the page).

With the introduction of the Fabric editor, support for plaintext bodies was handled by replacing the preview on the right-hand side of the macro editor with a text area, which can be accessed in the browser through AP.confluence.getMacroBody().

The Forge equivalent would likely be a <TextArea> in a <MacroConfig> just like any other macro parameter, but there presumably would need to be some way of linking existing body content (created with the Connect version of the macro using either TinyMCE or Fabric) to this text area.

Perhaps something as simple as a reserved name, e.g. <TextArea name=“macroBody”/>?

3 Likes

@Atlassian-Staff
Is there any update on this issue. Following Case:

(1) Server App with MacroBody of type plain-text.
(2) Cloud App with Forge (no macro body)

=> When a customer migrates from server to cloud now and has several macros with macro-body in their pages
=> What should happen in Cloud? How can I migrate this from P2 Server to Cloud Forge App?

1 Like

@clouless about the following:

What should happen in Cloud? How can I migrate this from P2 Server to Cloud Forge App?

I’ve just created a new feature request for the migration team:
https://jira.atlassian.com/browse/MIG-771

This is where you can track progress on this part of the request.

Thanks,
Caterina

All, @clouless (because your comment is the most recent),

About the “macro body content”, the team would like to know more about the use cases for requesting that.

This request is also tracked on the https://ecosystem.atlassian.net/browse/FRGE-216 ticket.

In particular, it would help if you could share what is not possible today with the available options.
Keeping in mind that there is an option to use the config parameters and the Forge team would like to know the scenarios where these are not sufficient.

Thank you,
Caterina

Hi @ccurti ,

Thanks for answering here. As Dennis Fischer already wrote in
https://ecosystem.atlassian.net/browse/FRGE-216

There is no macroBody on Forge. And yes I know you can have parameters and all other fancy things, but there is no compatibility between (Server <-> Connect) <-> Forge Macros.

This will be a long post, since I think there is no common understanding what the problem is :slight_smile:

(1) Confluence Server Macro with Macro Body

  • As server macro has
  • (a) a macroKey that is unique and the app installed which has registered that macroKey will be rendered for the ac:structrured-macro with that key
  • (b) a macroBody that is stored inside the confluence page (see storage format of page) and is editable when editing the page
  • (c) macroParameters that are stored within the page as well and can be edited in edit mode
  • (d) macroId that can be used to extract the contentBody and Parameters via REST API from the page

The storage format looks like so:

<ac:structured-macro 
   ac:name="advanced-single-codeblock-macro" 
   ac:schema-version="1" 
   ac:macro-id="cc2655f2-3d33-48ff-a17f-f6eb3d7aa5a6"
>
  <ac:parameter ac:name="theme">light-spring</ac:parameter>
  <ac:parameter ac:name="lang">JSON</ac:parameter>
  <ac:parameter ac:name="globaltitle">My Codeblock</ac:parameter>
  <ac:plain-text-body><![CDATA[{
  "foo": "bar"
}]]></ac:plain-text-body>
</ac:structured-macro>

(2) Cloud Connect Macro

You can provide a 100% exact same macro with Connect Cloud dynamicContentMacro

https://developer.atlassian.com/cloud/confluence/modules/dynamic-content-macro/

You will also have:

  • (a) a macroKey
  • (b) a macroBody that is stored inside the confluence page (see storage format of page) and is editable when editing the page
  • (c) macroParameters that are stored within the page as well and can be edited in edit mode
  • (d) macroId that can be used to extract the contentBody and Parameters via REST API from the page

You will have the same storage format and a customer can export its confluence space via XML and import it in cloud and your macro will work 100%.

A atlassian-connect.json snippet of such looks like this:

"modules": {
  "dynamicContentMacros": [
    {
      "name": { "value": "Advanced Codeblocks Single" },
      "description": { "value": "Visualize a single codeblock without replacements" },
      "key": "advanced-single-codeblock-macro",
      "url": "/advanced-single-codeblock-macro?pageId={page.id}&macroId={macro.id}&spaceKey={space.key}&pageVersion={page.version}",
      "categories": ["development"],
      "outputType": "block",
      "bodyType": "plain-text",
      "icon": { ... },
      "alias": "advanced-single-codeblock-macro",
      "parameters": [
        { ... }
      ]
    }
  ]
}
  • See the bodyType=plain-text.
  • Server and Cloud Connect both have
    • macroKey
    • macroBody
    • macroParams
    • macroId
    • same storage format as ac:structured-macro
  • => Server to Cloud Connect migration works out of the box!

(3) Forge Macro

A Forge macro has:

  • a completely different storage format
  • no macroKey in the form of CloudConnect and Server (some uuid thing that might be different on each installation)
  • no macroBody
  • params that are stored differently

Storage format of forge macro

<ac:adf-extension>
  <ac:adf-node type="extension">
    <ac:adf-attribute key="extension-type">com.atlassian.ecosystem</ac:adf-attribute>
    <ac:adf-attribute key="extension-key">889977.../static/advanced-codeblocks-hello-world</ac:adf-attribute>
    <ac:adf-attribute key="parameters">
      <ac:adf-parameter key="local-id">e31a0637-...</ac:adf-parameter>
      <ac:adf-parameter key="extension-id">ari:cloud:ecosystem::extension/889977.../static/advanced-codeblocks-hello-world</ac:adf-parameter>
      <ac:adf-parameter key="extension-title">advanced-codeblocks (Development)</ac:adf-parameter>
      <ac:adf-parameter key="guest-params">
        <ac:adf-parameter key="macro-body">// my code block
const foo = &quot;bar&quot;;</ac:adf-parameter>
      </ac:adf-parameter>
    </ac:adf-attribute>
    <ac:adf-attribute key="text">advanced-codeblocks (Development)</ac:adf-attribute>
    <ac:adf-attribute key="layout">full-width</ac:adf-attribute>
    <ac:adf-attribute key="local-id">648062b5-....</ac:adf-attribute>
  </ac:adf-node>
  <ac:adf-fallback>
    <ac:adf-node type="extension">
      <ac:adf-attribute key="extension-type">com.atlassian.ecosystem</ac:adf-attribute>
      <ac:adf-attribute key="extension-key">889977.../static/advanced-codeblocks-hello-world</ac:adf-attribute>
      <ac:adf-attribute key="parameters">
        <ac:adf-parameter key="local-id">e31a0637-...</ac:adf-parameter>
        <ac:adf-parameter key="extension-id">ari:cloud:ecosystem::extension/889977.../static/advanced-codeblocks-hello-world</ac:adf-parameter>
        <ac:adf-parameter key="extension-title">advanced-codeblocks (Development)</ac:adf-parameter>
        <ac:adf-parameter key="guest-params">
          <ac:adf-parameter key="macro-body">// my code block
const foo = &quot;bar&quot;;</ac:adf-parameter>
        </ac:adf-parameter>
      </ac:adf-attribute>
      <ac:adf-attribute key="text">advanced-codeblocks (Development)</ac:adf-attribute>
      <ac:adf-attribute key="layout">full-width</ac:adf-attribute>
      <ac:adf-attribute key="local-id">648062b5-....</ac:adf-attribute>
    </ac:adf-node>
  </ac:adf-fallback>
</ac:adf-extension>

Problems with Server to Cloud Forge XOR Cloud Connect to Cloud Forge migration:

Situation:

  • Customer imports Confluence Export as XML in his cloud space.
  • Pages contain ac:structured-macro storage format with server macro
  • Pages render “unknown macro” (because forge macro reacts to its ac:adf-extension storage format)

What needs a solution:

  • When importing a Server Confluence Space to Cloud (XOR When customer has already Cloud Connect app and App Vendor wants to switch to forge)
  • (I) Then how is the ac:structured-macro storage format migrated to the new ac:adf-extension storage format?
  • (II) Then how is the plainText macroBody made available to a forge macro that has no plainText macroBody? (At best you make it available as it is available in Cloud Connect)
  • (III) Then how is the macroParams made available to a forge macro?

I suggest that you really develop a tiny confluence Server macro with plainText macroBody and some params and actually test how to provide an automated migration path to a forge macro.
I think there are a lot of macros in the Marketplace that use macroBody and have currently no way to migrate to forge.

I hope that makes things clearer :slight_smile:


UPDATE: My Suggestions:

  • (I) automatically convert ac:structured-macro storage format to ac:adf-extension storage format with the following conversions:
  • (II) convert the ac:storage-format macroBody to an ac:adf-extension guest parameters with special name like macroBody. e.g.:
    <ac:adf-attribute key="parameters">
      <ac:adf-parameter key="guest-params">
        <ac:adf-parameter key="macro-body">// my code block
const foo = &quot;bar&quot;;</ac:adf-parameter>
      </ac:adf-parameter>
    </ac:adf-attribute>
  • (III) convert ac:storage-format macro params to equally named ac:adf-extension guest parameters.
    <ac:adf-attribute key="parameters">
      <ac:adf-parameter key="guest-params">
        <ac:adf-parameter key="macro-body">...</ac:adf-parameter>
        <ac:adf-parameter key="theme">light-spring</ac:adf-parameter>
        <ac:adf-parameter key="lang">JSON</ac:adf-parameter>
      </ac:adf-parameter>
    </ac:adf-attribute>

Cheers,

Bernhard

14 Likes

Very nice, detailed, clear, concise post Bernhard!

1 Like