Eidos

Installation Notice

The installation may currently fail. We recommend copying the code below and creating the extension manually in Eidos.

bpmn2Eidos

By: j0t4

Install Latest (v0.0.1)

This is a Bpmn2 Modeler in Eidos

import { throttle } from 'lodash';
import BpmnModeler from 'bpmn-js/dist/bpmn-modeler.production.min.js';
import { useEffect, useRef, useMemo } from "react"; 
import "bpmn-js/dist/assets/diagram-js.css";
import "bpmn-js/dist/assets/bpmn-js.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";

export const meta = {
  type: "extNode",
  componentName: "bpmn2Eidos",
  extNode: {
    title: "Bpmn2 Modeler in Eidos",
    description: "This is a Bpmn2 Modeler in Eidos",
    type: "bpmn2",
  },
}

export function BPMNModelerEidos() {
  const nodeId = window.location.pathname.split("/")[1];
  const canvasRef = useRef(null);
  const modelerRef = useRef(null);

  
  const throttledSave = useMemo(() => throttle(async () => {
    if (modelerRef.current) {
      try {
        const { xml } = await modelerRef.current.saveXML({ format: true });
        await eidos.currentSpace.extNode.setText(nodeId, xml);
        // console.log("Diagram auto-saved!"); // Optional: for debugging
      } catch (err) {
        console.error("Error saving BPMN diagram:", err);
      }
    }
  }, 500, { trailing: true }), [nodeId]); 

  useEffect(() => {
    modelerRef.current = new BpmnModeler({
      container: canvasRef.current
    });

    const eventBus = modelerRef.current.get('eventBus');
    eventBus.on('commandStack.changed', throttledSave);
    
    const loadSavedDiagram = async () => {
      try {
        var Xml = await eidos.currentSpace.extNode.getText(nodeId);
        if (!Xml) { Xml = sampleBPMNXML }
        await modelerRef.current.importXML(Xml);
      } catch (err) {
        console.error("Error loading BPMN diagram:", err);
      }
    };
   
    loadSavedDiagram();
   
    return () => {
      modelerRef.current.get('eventBus').off('commandStack.changed', throttledSave);
      modelerRef.current.destroy();
     };
   
  }, [nodeId, throttledSave]); 

  // The manual save function can be kept or removed

  const downloadCurrentDiagram = async () => {
    const { xml } = await modelerRef.current.saveXML({ format: true });
    await eidos.currentSpace.extNode.setText(nodeId, xml);
    const blob = new Blob([xml ?? ""], { type: "application/xml" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = "my-diagram.bpmn";
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
      {/* You can keep or remove this button, as saving is now automatic */}
      <div><button onClick={downloadCurrentDiagram}>Save Manually</button></div>
      <div style={{ flex: "1 1 auto" }}>
        <div ref={canvasRef} style={{ width: "100%", height: "100%" }} />
      </div>
    </div>
  );
}

const sampleBPMNXML = `<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn">
  <bpmn:process id="Process_1" isExecutable="false">
    <bpmn:startEvent id="Event_0wiwif7" />
  </bpmn:process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_1">
    <bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Process_1">
      <bpmndi:BPMNShape id="Event_0wiwif7_di" bpmnElement="Event_0wiwif7">
        <dc:Bounds x="182" y="152" width="36" height="36" />
      </bpmndi:BPMNShape>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>`;

Information

Author
j0t4
Type
block
Latest Version
0.0.1
Last Updated
10/09/2025
Published
10/09/2025

Version History

  • v0.0.1 10/09/2025