Perfect! Let me help you implement the DOM event approach for the client side with a React component.
Client Plugin with React Component
Here’s how to structure your client plugin to listen for DOM events and update your React component:
1. Main Client Plugin File (client.js)
import React from 'react';
import ReactDOM from 'react-dom';
import { registerBpmnJSPlugin } from 'camunda-modeler-plugin-helpers';
import GitStatusBar from './GitStatusBar'; // Your React component
// Create a container for your status bar component
let statusBarContainer = null;
let gitStatusComponent = null;
function GitIntegrationPlugin(eventBus, canvas) {
// Initialize the status bar when the modeler is ready
eventBus.on('import.done', function() {
if (!statusBarContainer) {
createStatusBar(canvas);
}
});
// Listen for git branch changes from menu plugin
window.addEventListener('git-branch-changed', (event) => {
const { branch } = event.detail;
if (gitStatusComponent) {
gitStatusComponent.updateBranch(branch);
}
});
// Request initial branch info when plugin loads
window.addEventListener('DOMContentLoaded', () => {
window.dispatchEvent(new CustomEvent('git-branch-request'));
});
}
function createStatusBar(canvas) {
// Create container in the modeler UI
const modelerContainer = canvas.getContainer().parentElement;
statusBarContainer = document.createElement('div');
statusBarContainer.id = 'git-status-bar';
statusBarContainer.style.cssText = `
position: absolute;
bottom: 10px;
right: 10px;
z-index: 1000;
`;
modelerContainer.appendChild(statusBarContainer);
// Render React component
gitStatusComponent = ReactDOM.render(
<GitStatusBar />,
statusBarContainer
);
}
// Register the plugin
registerBpmnJSPlugin({
__init__: ['gitIntegrationPlugin'],
gitIntegrationPlugin: ['type', GitIntegrationPlugin]
});
2. React Component (GitStatusBar.jsx)
import React, { useState, useEffect, useRef } from 'react';
const GitStatusBar = () => {
const [currentBranch, setCurrentBranch] = useState('unknown');
const [isLoading, setIsLoading] = useState(true);
const componentRef = useRef();
useEffect(() => {
// Listen for branch updates from menu plugin
const handleBranchChange = (event) => {
setCurrentBranch(event.detail.branch);
setIsLoading(false);
};
// Listen for initial branch response
const handleBranchResponse = (event) => {
setCurrentBranch(event.detail.branch);
setIsLoading(false);
};
window.addEventListener('git-branch-changed', handleBranchChange);
window.addEventListener('git-branch-response', handleBranchResponse);
// Request initial branch info
window.dispatchEvent(new CustomEvent('git-branch-request'));
// Cleanup
return () => {
window.removeEventListener('git-branch-changed', handleBranchChange);
window.removeEventListener('git-branch-response', handleBranchResponse);
};
}, []);
// Expose update method for direct calls (alternative approach)
useEffect(() => {
if (componentRef.current) {
componentRef.current.updateBranch = (branch) => {
setCurrentBranch(branch);
setIsLoading(false);
};
}
}, []);
const handleBranchClick = () => {
// Request branch refresh
setIsLoading(true);
window.dispatchEvent(new CustomEvent('git-branch-request'));
};
return (
<div
ref={componentRef}
style={{
backgroundColor: '#f0f0f0',
border: '1px solid #ccc',
borderRadius: '4px',
padding: '4px 8px',
fontSize: '12px',
cursor: 'pointer',
display: 'flex',
alignItems: 'center',
gap: '4px'
}}
onClick={handleBranchClick}
title="Click to refresh branch info"
>
<span>🌿</span>
{isLoading ? (
<span>Loading...</span>
) : (
<span>{currentBranch}</span>
)}
</div>
);
};
export default GitStatusBar;
3. Alternative: Using React Hooks for Event Handling
If you prefer a more React-like approach, create a custom hook:
// useGitBranch.js
import { useState, useEffect } from 'react';
export const useGitBranch = () => {
const [branch, setBranch] = useState('unknown');
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const handleBranchChange = (event) => {
setBranch(event.detail.branch);
setIsLoading(false);
};
const handleBranchResponse = (event) => {
setBranch(event.detail.branch);
setIsLoading(false);
};
window.addEventListener('git-branch-changed', handleBranchChange);
window.addEventListener('git-branch-response', handleBranchResponse);
// Request initial branch
window.dispatchEvent(new CustomEvent('git-branch-request'));
return () => {
window.removeEventListener('git-branch-changed', handleBranchChange);
window.removeEventListener('git-branch-response', handleBranchResponse);
};
}, []);
const refreshBranch = () => {
setIsLoading(true);
window.dispatchEvent(new CustomEvent('git-branch-request'));
};
return { branch, isLoading, refreshBranch };
};
// Then in your component:
const GitStatusBar = () => {
const { branch, isLoading, refreshBranch } = useGitBranch();
return (
<div onClick={refreshBranch}>
🌿 {isLoading ? 'Loading...' : branch}
</div>
);
};
4. Menu Plugin Side (for reference)
Your menu plugin should dispatch these events:
// In your menu plugin
function notifyBranchChange(branch) {
const windows = require('electron').BrowserWindow.getAllWindows();
windows.forEach(window => {
window.webContents.executeJavaScript(`
window.dispatchEvent(new CustomEvent('git-branch-changed', {
detail: { branch: '${branch}' }
}));
`);
});
}
// Listen for branch requests
function setupBranchRequestListener() {
const windows = require('electron').BrowserWindow.getAllWindows();
windows.forEach(window => {
window.webContents.executeJavaScript(`
window.addEventListener('git-branch-request', () => {
// This will be handled by your menu plugin logic
});
`);
});
}
This approach gives you:
- Clean React component that responds to git branch changes
- Event-driven communication between menu and client plugins
- Ability to refresh branch info on demand
- Proper cleanup of event listeners
Would you like me to help you with the menu plugin side implementation, or do you have questions about integrating this with your existing React component?