NotesWhat is notes.io?

Notes brand slogan

Notes - notes.io

Description
Scope: Create a reusable mechanism for launching an extension-B from extension-A, also for sending data between extensions.
Use the documentation about cross messaging for communicating iframes between window objects.
 https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage
 https://stackoverflow.com/questions/9153445/how-to-communicate-between-iframe-and-the-parent-site
 https://www.bryanbraun.com/2021/03/24/infinitely-nested-iframes/ --> If there is a particular case where extension-A *loads* extension-B *loads* extension-A *loads* extension-B etc...
Brief
• Blackboard extensions are React applications that can be run as standalone apps or being called by other running app.
A current implemented example is the launching of userWorkflowManager app inside programView app.

• The current image shows the following:
o programView (pv) is the parent app which has launched userWorkflowManager (uwm) app inside an iframe in detached mode when you click the Sign up button. In this case the AccountCreation peekpanel from uwm is rendering a detached view.
o The launched iframe child app uwm overlays the full root app pv, with fixed position, full width and height and with a transparent background for generating the effect we are on the same root app.
o To notify the child app which view needs to be rendered, two technologies are used:
 The builtin cross messaging browser apis for communicating iframes between window objects.
 react-router-dom, where parent app post a message to child (iframe) app, the message is the route path for rendering a detached view.
Development setup
• To simulate calling extension-b from extension-a, both extension needs to be running on your local machine.
o cd to extension-a and extension-b and run the command npm run start respectively to start each one of them.
o Each extension has a .env.example file, create on the same file level a .env.dev file with the following url paths:
o
o BA_DEV_URL=http://localhost:4100
o MP_DEV_URL=http://localhost:4200
o PG_DEV_URL=http://localhost:4300
o PV_DEV_URL=http://localhost:4400
o TI_DEV_URL=http://localhost:4500
o UWM_DEV_URL=http://localhost:4600
o .env.dev will contain the local urls of each running extension, to simulate locally launching another app inside an iframe.
Provider setup
• On every CSTP index.tsx extension must be implemented the <CstpCrossWindowProvider> which provides apis developed by BB team for:
o Launching an external CSTP extension using an iframe.
o Communication between parent extension and child extension (iframe).
o Note: <CstpCrossWindowProvider> needs to be added inside redux and router providers to work.

ReactDOM.render(
<Provider store={store}>
<Router>
<CstpCrossWindowProvider>
<App />
</CstpCrossWindowProvider>
</Router>
</Provider>,
document.getElementById('root'),
);
Preparing every App to be mounted as an iframe
• Inside any extension App.tsx needs to be added:
o isStandalone(): function to check if the application is running in standalone mode (launched directly from the browser) or is an embedded extension (launched from an iframe).
o useNavigateCrossWindow(): this hook only works when the current extension is launched as an iframe and has two main responsabilities:
 notifies to the parent extension that the app has been mounted from the iframe.
 listen the parent signal which contains the route for opening the detached view of the current running extension.

//Example from userWorkflowManager App.tsx
export const App: React.FC = () => {
const navigate = useNavigate();
const router = useRoutes(mainRoutes);
const settingModel = useSettingModel();
//If uwm is launched inside an iframe, the following hook:
//Notifies to the parent that uwm is mounted
//Listens the parent sent route to be opened inside uwm
useNavigateCrossWindow(); //This hook is part of shared component library
const { navigateOnParentSignal } = useNavigateCrossWindow();

/**
* Runs the different processes in parallel when the component is mounted.
*/
const onMounted = async () => {
//Add inside the promise all, the async processes that are needed to run when mounted.
await Promise.all([settingModel.list()]);

//isStandalone() detects if the application is running in standalone mode (true) or inside an iframe (false).
if (isStandalone()) {
navigate(`${ADMIN_ROUTE}`);
} else {
//Navigates to the route provided by the parent extension
navigateOnParentSignal();
}
};

useEffect(() => {
onMounted();
}, []);

return router;
};
Setting a detached view
• Detached views are ui rendered with a transparent background. It will create the effect that the launched view inside of an iframe is part of the current running app.
• Detached routes needs to be defined at src/routes/detachedRoutes.tsx file. Inside of it, register the routes that needs to be rendered isolately:

//Example from userWorkflowManager detachedRoutes.tsx
export const detachedRoutes: RouteObject[] = [...userRegistrationRoutes, ...anyOtherRoutes];
• For loading detached routes, they must be registered at src/routes/mainRoutes.tsx file.

• //Example from userWorkflowManager mainRoutes.tsx
• export const mainRoutes: RouteObject[] = [
• //Here are registered the standalone app routes
• {
• path: ROOT_ROUTE,
• element: <Public />,
• children: [
• {
• path: PUBLIC_ROUTE,
• element: <Public />,
• children: [...userRegistrationRoutes],
• },
• {
• path: ADMIN_ROUTE,
• element: <Admin />,
• children: [...adminRoutes],
• },
• //... more standalone routes to register
• ],
• },
• //Here are registered the detached routes (when app is running inside an iframe)
• {
• path: DETACHED_ROUTE, //DETACHED_ROUTE is a constant from shared components lib
• element: <DetachedOutlet />, //This outlet from shared components lib renders every view on a transparent background
• children: [...detachedRoutes, ...anyOtherRoutes], //Component routes to be rendered
• },
• ];
• For more information about how routes works, please refer to react-router-dom v6 docs.
Implementation example
• For this example programView (pv) is the parent and userWorkflowManager (uwm) is the child (iframe) app.
• When clicked the Sign up button, it will open the Account Creation peek panel from userWorkflowManager (uwm)

Parent app implementation PV
• The Sign up button has the following logic at programView/src/pages/TDM/HomePage/BarComponent/index.tsx

• //Inside BarComponent component from programView

• const cstp = useCstpCrossWindowContext(); //Contains the apis for cross window communication

• const signUp = async () => {
• setLoading(true);
• // Launches uwm extension and opens the detached route user-registration which
• // renders the account creation peek panel. For making launchApp to work and open uwm,
• // remember that useNavigateCrossWindow() needs to be implemented at uwm App.tsx file.
• // Also the user-registration detached route must be registered as was explained before.
• const uwmApp = await cstp.launchApp('userWorkflowManager', {
• route: 'user-registration',
• });
• setLoading(false);

• // When account is created, uwm app is unmounted.
• // The event uwm:accountCreationPeekPanelClose is sent by the iframe app, so the parent is waiting
• // to this event to be emmited for closing uwm extension (hide the uwm iframe).
• uwmApp.on('uwm:accountCreationPeekPanelClose', () => {
• uwmApp.unmountApp();
• });
• };
Child app implementation UWM
• The following code is implemented at userWorkflowManager/src/pages/Public/UserRegistration/index.tsx
• UserRegistration is the account creation peek panel. Inside of it was implemented a method for post to the parent extension PV when the peek panel
is closed with the event uwm:accountCreationPeekPanelClose

• // At line 44 more or less
• const { getCurrentApp } = useCstpCrossWindowContext();

• // At line 106 more or less
• // Renders the account creation success alert.
• // After confirming, peek panel is closed and after close callback
• // emits the signal to parent extension for unmounting the iframe
• const createAccount = async () => {
• ...
• await showSuccessAlert();
• peekPanel.close();
• ...
• };

• // At line 205 more or less
• // At peek panel after close, is set a callback for notifying
• // when to unmount the iframe when the peek panel close
• // or cancel buttons are pressed.
• useEffect(() => {
• peekPanel.afterClose(() => {
• getCurrentApp().postToParent({
• event: 'uwm:accountCreationPeekPanelClose',
• });
• });
• }, []);
Adding more events
• uwm:accountCreationPeekPanelClose is a typed event from shared-component-lib. Events must be typed for easing at future code debugging, so we can track better where the cross extension communication event comes from.
• For example if we need to create a communication between PV and Payment Gateway extensions, a posible event that needs to be defined is pg:paymentFinished, following the next nomenclature: extensionInitials:eventName.
• Events must be typed on shared component library at packages/frontend-services/src/interfaces/BbAppEvent.ts
• For every extension events create a type as for example BBUwmAppEvent or BBPvAppEvent
Sending and receiving data through extensions
• Send data from child extension to parent extension

• //Code from child extension

• getCurrentApp().postToParent({
• event: 'extensionInitials:eventName',
• data: {} //any data you need to sent
• });
• Receive data emitted by child extension from parent extension.

• //Code from parent extension

• childApp.on('extensionInitials:eventName', (data) => {
• console.log(data) //data emitted from child app
• });
• Send data from parent extension to child extension

• //Code from parent extension

• childApp.post({
• event: 'extensionInitials:eventName',
• data: {} //any data you need to sent
• });
• Receive data emitted by parent extension from child extension.

• //Code from child extension

• getCurrentApp().onParentSignal('extensionInitials:eventName', (data) => {
• console.log(data) //data emitted from parent app
• });
Code tours
• You can visualize this current implementation with Visual Studio Code - Code Tour extension
• Make sure you have installed the extension and restarted VSCode for visualizing the code tours.
• At left sidebar, open Code Tours and click the play button for:
o Communication between extensions
o Launching pwd settings from pv - iframe
Estimated time: 40h

     
 
what is notes.io
 

Notes.io is a web-based application for taking notes. You can take your notes and share with others people. If you like taking long notes, notes.io is designed for you. To date, over 8,000,000,000 notes created and continuing...

With notes.io;

  • * You can take a note from anywhere and any device with internet connection.
  • * You can share the notes in social platforms (YouTube, Facebook, Twitter, instagram etc.).
  • * You can quickly share your contents without website, blog and e-mail.
  • * You don't need to create any Account to share a note. As you wish you can use quick, easy and best shortened notes with sms, websites, e-mail, or messaging services (WhatsApp, iMessage, Telegram, Signal).
  • * Notes.io has fabulous infrastructure design for a short link and allows you to share the note as an easy and understandable link.

Fast: Notes.io is built for speed and performance. You can take a notes quickly and browse your archive.

Easy: Notes.io doesn’t require installation. Just write and share note!

Short: Notes.io’s url just 8 character. You’ll get shorten link of your note when you want to share. (Ex: notes.io/q )

Free: Notes.io works for 12 years and has been free since the day it was started.


You immediately create your first note and start sharing with the ones you wish. If you want to contact us, you can use the following communication channels;


Email: [email protected]

Twitter: http://twitter.com/notesio

Instagram: http://instagram.com/notes.io

Facebook: http://facebook.com/notesio



Regards;
Notes.io Team

     
 
Shortened Note Link
 
 
Looding Image
 
     
 
Long File
 
 

For written notes was greater than 18KB Unable to shorten.

To be smaller than 18KB, please organize your notes, or sign in.