Skip to main content

Team,

I am developing a LucidChart extension package.  It has editor extension, shape library, etc. Within my editor extension, I will be using Modal and Panel that gets its content from React.  I need the Lucid parent Modal or Panel to send data to child React app where the user will make some edits.  After editing, the child react form will send back to the parent Modal or Panel.

I have followed the documentation but the end result is very inconsistent.  Sometimes the react app gets the message and sometimes it does not.  Maybe I have implemented it wrong.

The package code, including the React app can be found in this public Repo:

https://github.com/GreenShoesLLC/lucidchart_package_test

Here are the details.

When the user clicks on a shape, the test package adds a menu that when clicked, shows the following Lucid Modal.

 

import {
EditorClient,
Modal, Viewport
} from 'lucid-extension-sdk';

export class EditorModal extends Modal {
constructor(client: EditorClient) {
super(client, {
title: 'Hello world',
width: 400,
height: 300,
url: 'quodsim-react/index.html',
});

const viewport = new Viewport(client);
const selection = viewport.getSelectedItems();
const q_objecttype = selectione0].shapeData.get('q_objecttype');
console.log("Selected object type:", q_objecttype);

this.sendMessage({
messagetype: 'lucidchartdata',
simtype: q_objecttype,
version: '1',
instancedata: JSON.stringify({ id: '123', capacity: 3, name: 'blah' })
}).then(() => {
console.log("lucidchartdata Message sent successfully");
}).catch((error) => {
console.error("Failed to send lucidchartdata message:", error);
});
}

protected messageFromFrame(message: any): void {
console.log('Message from iframe:', message);

if (message.messagetype === 'activitySaved') {
const savedActivity = message.data;
console.log('Activity saved:', savedActivity);
// Handle the saved activity data here
// this.page.setTitle(`Activity Saved: ${savedActivity.name}`);
this.hide();
}
}
}

Notice the “this.sendMessage” call in the constructor of the EditorModal.  Also notice the url of the modal is linking to the React app.

My intent with the React code is to receive the sent message and based upon a value in the message, show the proper edit form.

Here is the receiving React code’s App.tsx file.

import React, { useState, useEffect } from 'react';
import ActivityEditor from './components/ActivityEditor';
import EntityEditor from './components/EntityEditor';
import ConnectorEditor from './components/ConnectorEditor';
import { Activity, Entity, Connector, SimulationObjectType } from './app/models';

const App: React.FC = () => {
const beditor, setEditor] = useState<JSX.Element | null>(null);

const handleMessage = (data: any) => {

// console.log(`handleMessage called with data: ${JSON.stringify(data)}`);
// console.log("handleMessage called", { data });
console.log("handleMessage called with data:", data);

if (data.messagetype === 'lucidchartdata') {
const instanceData = JSON.parse(data.instancedata);
console.log("instanceData:", instanceData);
switch (data.simtype) {
case 'activity':
console.log("setEditor to ActivityEditor")
setEditor(
<ActivityEditor
activity={instanceData as Activity}
onSave={(activity) => console.log(JSON.stringify(activity))}
onCancel={() => setEditor(null)}
/>
);
break;
case 'entity':
console.log("setEditor to EntityEditor")
setEditor(
<EntityEditor
entity={instanceData as Entity}
onSave={(entity) => console.log(JSON.stringify(entity))}
onCancel={() => setEditor(null)}
/>
);
break;
case 'connector':
console.log("setEditor to ConnectorEditor")
setEditor(
<ConnectorEditor
connector={instanceData as Connector}
onSave={(connector) => console.log(JSON.stringify(connector))}
onCancel={() => setEditor(null)}
/>
);
break;
}
}
};

useEffect(() => {
console.log('Adding message event listener');
const eventListener = (event: MessageEvent) => {
console.log('Received message event:', event);
handleMessage(event.data);
};
window.addEventListener('message', eventListener);
return () => {
console.log('Removing message event listener');
window.removeEventListener('message', eventListener);
};
}, }]);

const sendTestMessage = (type: SimulationObjectType) => {
let testData;
switch (type) {
case SimulationObjectType.Activity:
testData = {
messagetype: 'lucidchartdata',
simtype: 'activity',
version: '1',
instancedata: JSON.stringify({ id: '123', capacity: 3, name: 'Test Activity', type: SimulationObjectType.Activity })
};
break;
case SimulationObjectType.Entity:
testData = {
messagetype: 'lucidchartdata',
simtype: 'entity',
version: '1',
instancedata: JSON.stringify({ id: '456', name: 'Test Entity', type: SimulationObjectType.Entity })
};
break;
case SimulationObjectType.Connector:
testData = {
messagetype: 'lucidchartdata',
simtype: 'connector',
version: '1',
instancedata: JSON.stringify({ id: '789', fromActivityId: '123', toActivityId: '456', name: 'Test Connector', type: SimulationObjectType.Connector })
};
break;
}
handleMessage(testData);
};

return (
<div>
{!editor && (
<div>
<button onClick={() => sendTestMessage(SimulationObjectType.Activity)}>Test Activity2</button>
<button onClick={() => sendTestMessage(SimulationObjectType.Entity)}>Test Entity2</button>
<button onClick={() => sendTestMessage(SimulationObjectType.Connector)}>Test Connector2</button>
</div>
)}
{editor}
</div>
);
};

export default App;

Notice the useEffect has the window.addEventListener('message', eventListener);  Also notice I have added extension console log statements.

Most of the time, the received message is this:

{type: 'webpackOk', data: undefined}

Every once and while, I will actually successfully receive the desired message.

{
    "messagetype": "lucidchartdata",
    "simtype": "activity",
    "version": "1",
    "instancedata": "{\"id\":\"123\",\"capacity\":3,\"name\":\"activity1\"}"
}

My development workstation is Windows.  I am hoping someone can pull down the repo and see if they get the same inconsistent behavior.

I use “Npx react-scripts start” in 

\lucidchart_package_test\editorextensions\quodsi_editor_extension\quodsim-react

 

“npx lucid-package@latest test-editor-extension quodsi_editor_extension” in:

\lucidchart_package_test;

Hello PromitaDan,

 

We are reviewing your question and will have some feedback as soon as find something helpful.


I have a work around right now.  Basically, in my react code, AFTER app.tsx establishes the useeffect for receiving messages, it sends a “ready” message to the parent iframe.  The extension.ts is waiting on receiving the “ready” message before it sends the data to the child react app.  This is now consistently working.

Thoughts?

dan


I’m glad to hear you got a solution. We have not had a chance to pull your code and try to recreate.  Let me know if you continue to see these types of issues.


Reply