Last active
September 12, 2025 07:24
-
-
Save engalar/b84b71693c4d1a8addd458e4eec53da3 to your computer and use it in GitHub Desktop.
studio pro plugin for tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- https://gist.github.com/engalar/b84b71693c4d1a8addd458e4eec53da3 --> | |
<!-- gh gist edit b84b71693c4d1a8addd458e4eec53da3 .\index.html -f index.html --> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Simple plugin demo</title> | |
<!-- 框架依赖: React, Tailwind, Babel, VConsole (引入本地资源,以便离线使用) --> | |
<script src="assets/react.development.js"></script> | |
<script src="assets/react-dom.development.js"></script> | |
<script src="assets/tailwindcss.js"></script> | |
<script src="assets/babel.min.js"></script> | |
<script src="assets/vconsole.min.js"></script> | |
<script>new VConsole();</script> | |
</head> | |
<body class="bg-gray-100 font-sans"> | |
<div id="app"></div> | |
<script type="text/babel"> | |
const { useState, useEffect } = React; | |
function App() { | |
const [inputValue, setInputValue] = useState(''); | |
const [receivedMessages, setReceivedMessages] = useState([]); | |
// Function to send messages to the Mendix Studio Pro backend | |
const sendMessageToBackend = () => { | |
if (inputValue.trim() === '') { | |
return; | |
} | |
// Construct the message object to send | |
// The backend's onMessage function expects a 'Data' field which will be our message_object | |
// The C# host environment will wrap the second argument into e.Data | |
const messageObject = { | |
timestamp: new Date().toISOString(), | |
content: inputValue, | |
sender: 'frontend' | |
}; | |
// Send the message to the C# host, which forwards it to the Python backend | |
window.parent.sendMessage("frontend:message", messageObject); | |
setInputValue(''); // Clear the input field | |
}; | |
// Effect hook to set up and tear down the message event listener | |
useEffect(() => { | |
const handleBackendResponse = (event) => { | |
if (event.data && event.data.type === 'backendResponse') {//对应后端的PostMessage("backend:response", json.dumps(response)) | |
try { | |
const payloadString = event.data.data; | |
// Parse the JSON string received from the backend | |
const payload = JSON.parse(payloadString); | |
setReceivedMessages((prevMessages) => [...prevMessages, payload]); | |
} catch (error) { | |
console.error("Error parsing backend response:", error); | |
// Optionally display an error message in the UI | |
} | |
} | |
}; | |
// Add the event listener for messages from the host | |
window.addEventListener('message', handleBackendResponse); | |
// Cleanup function to remove the event listener when the component unmounts | |
return () => { | |
window.removeEventListener('message', handleBackendResponse); | |
}; | |
}, []); // Empty dependency array ensures this runs once on mount and once on unmount | |
return ( | |
<div className="p-4 max-w-2xl mx-auto bg-white shadow-lg rounded-lg mt-8"> | |
<h1 className="text-3xl font-bold text-gray-800 mb-6">Mendix Plugin Demo</h1> | |
<div className="flex mb-6"> | |
<input | |
type="text" | |
className="flex-grow p-3 border border-gray-300 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-gray-700" | |
value={inputValue} | |
onChange={(e) => setInputValue(e.target.value)} | |
onKeyPress={(e) => { | |
if (e.key === 'Enter') { | |
sendMessageToBackend(); | |
} | |
}} | |
placeholder="Type a message to send to the backend..." | |
/> | |
<button | |
onClick={sendMessageToBackend} | |
className="px-6 py-3 bg-blue-600 text-white font-semibold rounded-r-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 transition duration-200" | |
> | |
Send | |
</button> | |
</div> | |
<div> | |
<h2 className="text-2xl font-semibold text-gray-800 mb-3">Received from Backend:</h2> | |
{receivedMessages.length === 0 ? ( | |
<p className="text-gray-600 italic">No messages received yet. Send something!</p> | |
) : ( | |
<div className="bg-gray-50 p-4 rounded-lg border border-gray-200 h-64 overflow-y-auto"> | |
{receivedMessages.map((msg, index) => ( | |
<div key={index} className="mb-3 p-3 bg-white rounded-md shadow-sm last:mb-0"> | |
<pre className="text-sm text-gray-800 whitespace-pre-wrap font-mono"> | |
{JSON.stringify(msg, null, 2)} | |
</pre> | |
</div> | |
))} | |
</div> | |
)} | |
</div> | |
</div> | |
); | |
} | |
const root = ReactDOM.createRoot(document.getElementById('app')); | |
root.render(<App />); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://gist.github.com/engalar/b84b71693c4d1a8addd458e4eec53da3 | |
# gh gist edit b84b71693c4d1a8addd458e4eec53da3 .\main.py -f main.py | |
# pip install pythonnet dependency-injector | |
from Mendix.StudioPro.ExtensionsAPI.Model.DomainModels import AssociationDirection, IDomainModel, IEntity, IAttribute, IAttributeType, IStoredValue, IAssociation, IIntegerAttributeType | |
from Mendix.StudioPro.ExtensionsAPI.Model.Pages import IPage | |
from Mendix.StudioPro.ExtensionsAPI.Model.Microflows import IMicroflow | |
from Mendix.StudioPro.ExtensionsAPI.Model.Projects import IProject, IModule, IFolder | |
import clr | |
from System.Text.Json import JsonSerializer | |
import json | |
from typing import Any, Dict, List, Protocol | |
# pythonnet库嵌入C#代码 | |
clr.AddReference("System.Text.Json") | |
clr.AddReference("Mendix.StudioPro.ExtensionsAPI") | |
# 运行时环境提供的工具 | |
PostMessage("backend:clear", '') # 清理IDE控制台日志 | |
ShowDevTools() # 打开前端开发者工具 | |
# 运行时环境提供的上下文变量 | |
# currentApp:mendix model | |
# root:untyped model | |
# dockingWindowService | |
# region define | |
# fix c# json与python json转换问题 | |
def serialize_json_object(json_object: Any) -> str: | |
# 将.NET对象序列化为JSON字符串 | |
import System.Text.Json | |
return System.Text.Json.JsonSerializer.Serialize(json_object) | |
def deserialize_json_string(json_string: str) -> Any: | |
# 将JSON字符串反序列化为Python对象 | |
return json.loads(json_string) | |
# mendix model事务工具 | |
class TransactionManager: | |
"""with TransactionManager(currentApp, f"your transaction name"):""" | |
def __init__(self, app, transaction_name): | |
self.app = app # currentApp | |
self.name = transaction_name | |
self.transaction = None | |
def __enter__(self): | |
self.transaction = self.app.StartTransaction(self.name) | |
return self.transaction | |
def __exit__(self, exc_type, exc_val, exc_tb): | |
if exc_type is None: | |
self.transaction.Commit() | |
else: | |
self.transaction.Rollback() | |
self.transaction.Dispose() | |
return False # 允许异常继续传播 | |
# endregion | |
# 获取所有模块 | |
ms = currentApp.Root.GetModules() | |
# 获取名为Administration的模块 | |
m = next((m for m in ms if m.Name == 'Administration'), None) | |
# 获取名为Administration.Account的实体 | |
entity = next((e for e in m.DomainModel.GetEntities() | |
if e.Name == 'Account'), None) | |
# 编辑器打开模块Administration的DomainModel单元并选中Account实体 | |
ret = dockingWindowService.TryOpenEditor(m.DomainModel, entity) | |
PostMessage("backend:info", f"{ret}") | |
def onMessage(e: Any): | |
""" | |
接收来自C#的消息 | |
Args: | |
e (Any): The event object containing the message type and data from the frontend. | |
Returns: | |
None | |
""" | |
# 接收来自C#转发的前端消息,前端用window.parent.sendMessage("frontend:message", jsonMessageObj)发送消息 | |
if e.Message == "frontend:message": | |
try: | |
# FIX: Use the .NET JsonSerializer to handle the incoming .NET JsonObject (e.Data) | |
# This correctly converts the .NET object to a standard JSON string. | |
request_string = JsonSerializer.Serialize(e.Data) | |
# Now, use Python's json library to parse the string into a Python dictionary. | |
request_object = json.loads(request_string) | |
if request_object: | |
# 处理逻辑 | |
response = request_object # 简单的echo消息来模拟处理逻辑 | |
# 发送消息给前端,前端可以用如下代码来接收 | |
# window.addEventListener('message', (event) => { | |
# if (event.data && event.data.type === 'backendResponse') { | |
# const payload = event.data.data;// payload就是echo的response | |
# // your logic here | |
# } | |
# }) | |
PostMessage("backend:response", json.dumps(response)) | |
except Exception as ex: | |
PostMessage( | |
"backend:info", f"Fatal error in onMessage: {ex}\n{traceback.format_exc()}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "tutorial", | |
"author": "wengao", | |
"email": "[email protected]", | |
"ui": "index.html", | |
"plugin": "main.py" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment