Forge Custom UI - full screen view

Hi All,

I am in the process of migrating an existing Connect Macro App, Visio Publisher for Confluence over to Forge.

In summary the Forge App uses custom UI to render HTML content stored as a page attachment. The screenshot below shows the Forge app WIP

The existing Connect app has a link that launches the embedded HTML content in a new browser window (not shown in the Forge screenshot).

I can see that the router offers similar functionality but requires a relative or absolute URL (that I don’t have - the page attachment source is written to the window body in the Connect version).

Optionally, I have seen that Modal might be used. However, I haven’t been able to find a worked example of its use.

Is there any other option? Ideally I would like the UX to be similar to that when a user clicks “view” on the attachments page i.e. takes the whole screen real estate.

Cheers,
Andrew

Hello Andrew,

We use modal with its max size so that you have your complete own interaction with the user (just showing a bit of the page as “frame” that is also a bit grayed out). We just followed the example that is in the documentation with the modal - what’s not working there?

Best,
Eckhard

@AndrewTyson , you made a right assumptions about Modal. It is the only right way to achieve what you need and in fact not that difficult but takes time to understand.
In the example from the link index.js is the place where you want to open a window from, for example by button click. It will try to open a modal window using the resource you specify: resource: ‘my-modal-resource’.
This resource must be added to .yml like this:

  • key: my-modal-resource
    path: static/my-modal/build - this is another react app you need to build, but it is not a separate module in Forge.
    my-modal-resource.js - it is the resource in the example, but unfortunately it cannot be referenced like this (or at least I couldn’t) and you need to make a build folder.
    So you make an index.js inside static/my-modal/src and build it as usual. It should look like this
import React from 'react';
import ReactDOM from 'react-dom/client';
import '@atlaskit/css-reset';
import AppProvider from '@atlaskit/app-provider';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <AppProvider>
    <App />
  </AppProvider>
);

In App.jsx you first extract what you need from context:

useEffect(() => {
    view.getContext().then((context) => {
      console.log('context: ', context);
      const fieldValue= context?.extension?.fieldValue? ?? null;
      setFieldValue(fieldValue);
      }
    });
  }, []);

When closing the window you simply call

view.close({
        param1: value1,
        param2: value2,
      });

Good luck

1 Like

Thanks @AndreyLednev - you got me on the right track. I have posted my working code here for any others who may be encountering any issues:

The “open modal” button component. The htmlBody property is sourced from an attachment to the page that contains the Forge macro:

const OpenModalButton = ({htmlBody}) => {

  const [passedHtmlBody, setPassedHtmlBody] = useState(undefined);

  useEffect( () =>{
    setPassedHtmlBody(htmlBody);
  }, [passedHtmlBody, htmlBody]);

  const buttonClickHandler = () => {
    const modal = new Modal({
      resource: 'modal',
       onClose: (payload) => {
       },
       size: 'max',
       context : {
        htmlBody: {passedHtmlBody},
       }
    });
    modal.open(); 
  } // buttonClickHandler

  return (
  <button onClick={buttonClickHandler}>Open Modal</button>
 )
}

Modal App that retrieves the “htmlBody” and renders it in the modal dialog

function App() {
  const [htmlBody, setHtmlBody] = useState(undefined);

  useEffect( () => {
    view
      .getContext()
      .then( (context) => { 
        const payload = context?.extension?.modal?.htmlBody?.passedHtmlBody; 
        setHtmlBody(payload);
      });
  }, []);

  return (
    <>
    <button onClick={ () =>{ 
      view.close({ formValues: [],});
    }} >Close Modal</button>
    <AttachmentIframe htmlBody={htmlBody}/>
     </>
  );
}

Thanks and regards,
Andrew

Thanks @EckhardMaass 
 got it working