we can edit a bpmn diagram now w/ burnettk

This commit is contained in:
jasquat 2022-06-02 13:53:02 -04:00
parent 945d6e85b4
commit 7b52804639
5 changed files with 451 additions and 96 deletions

44
package-lock.json generated
View File

@ -11,6 +11,7 @@
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.27.2",
"bpmn-js": "^9.1.0",
"bpmn-js-properties-panel": "^1.1.1",
"react": "^18.1.0",
@ -4691,6 +4692,28 @@
"node": ">=12"
}
},
"node_modules/axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"dependencies": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
}
},
"node_modules/axios/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
@ -19921,6 +19944,27 @@
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz",
"integrity": "sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA=="
},
"axios": {
"version": "0.27.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
"integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
"requires": {
"follow-redirects": "^1.14.9",
"form-data": "^4.0.0"
},
"dependencies": {
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
}
}
},
"axobject-query": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",

View File

@ -6,6 +6,7 @@
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.27.2",
"bpmn-js": "^9.1.0",
"bpmn-js-properties-panel": "^1.1.1",
"react": "^18.1.0",

View File

@ -1,12 +1,19 @@
// import logo from './logo.svg';
import './App.css';
import BpmnModeler from 'bpmn-js';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
// import './App.css';
// import BpmnModeler from 'bpmn-js';
// import {
// BpmnPropertiesPanelModule,
// BpmnPropertiesProviderModule,
// } from 'bpmn-js-properties-panel';
//
import React, { useEffect, useState } from "react";
import Modeler from "bpmn-js/lib/Modeler";
import "bpmn-js/dist/assets/diagram-js.css";
import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
import axios from "axios";
import ReactEditor from "./react_editor"
function App(props) {
function App() {
// return (
// <div className="App">
// <header className="App-header">
@ -25,6 +32,146 @@ function App(props) {
// </header>
// </div>
// );
// from spiff backend
// const bpmnModeler = new BpmnModeler({
// container: '#canvas',
// propertiesPanel: {
// parent: '#properties'
// },
// additionalModules: [
// BpmnPropertiesPanelModule,
// BpmnPropertiesProviderModule
// ]
// });
//
// async function exportDiagram() {
// try {
// var data = await bpmnModeler.saveXML({ format: true });
// //POST request with body equal on data in JSON format
// fetch("/admin/process-models/{{ process_model.id }}/save/{{ file_name }}", {
// method: "POST",
// headers: {
// "Content-Type": "text/xml",
// },
// body: data.xml,
// })
// .then((response) => response.json())
// //Then with the data from the response in JSON...
// .then((data) => {
// console.log("Success:", data);
// })
// //Then with the error genereted...
// .catch((error) => {
// console.error("Error:", error);
// });
//
// alert("Diagram exported. Check the developer tools!");
// } catch (err) {
// console.error("could not save BPMN 2.0 diagram", err);
// }
// }
//
// #<{(|*
// * Open diagram in our modeler instance.
// *
// * @param {String} bpmnXML diagram to display
// |)}>#
// async function openDiagram(bpmnXML) {
// // import diagram
// try {
// await bpmnModeler.importXML(bpmnXML);
//
// // access modeler components
// var canvas = bpmnModeler.get("canvas");
// var overlays = bpmnModeler.get("overlays");
//
// // zoom to fit full viewport
// canvas.zoom("fit-viewport");
//
// // attach an overlay to a node
// overlays.add("SCAN_OK", "note", {
// position: {
// bottom: 0,
// right: 0,
// },
// html: '<div class="diagram-note">Mixed up the labels?</div>',
// });
//
// // add marker
// canvas.addMarker("SCAN_OK", "needs-discussion");
// } catch (err) {
// console.error("could not import BPMN 2.0 diagram", err);
// }
// }
//
// // trying to use the python variable bpmn_xml directly causes the xml to have escape sequences
// // and using the meta tag seems to help with that
// // var bpmn_xml = $("#bpmn_xml").data();
// openDiagram({process.env.PUBLIC_URL + '/sample.bpmn'});
//
// // wire save button
// $("#save-button").click(exportDiagram);
// const [diagram, diagramSet] = useState("");
// const container = document.getElementById("container");
//
// useEffect(() => {
// if (diagram.length === 0) {
// axios
// .get(
// "https://cdn.staticaly.com/gh/bpmn-io/bpmn-js-examples/master/colors/resources/pizza-collaboration.bpmn"
// )
// .then((r) => {
// diagramSet(r.data);
// })
// .catch((e) => {
// console.log(e);
// });
// }
// }, [diagram]);
//
// if (diagram.length > 0) {
// const modeler = new Modeler({
// container,
// keyboard: {
// bindTo: document
// }
// });
// modeler
// .importXML(diagram)
// .then(({ warnings }) => {
// if (warnings.length) {
// console.log("Warnings", warnings);
// }
//
// const canvas = modeler.get("modeling");
// canvas.setColor("CalmCustomerTask", {
// stroke: "green",
// fill: "yellow"
// });
// })
// .catch((err) => {
// console.log("error", err);
// });
// }
//
// return (
// <div className="App">
// <div
// id="container"
// style={{
// border: "1px solid #000000",
// height: "90vh",
// width: "90vw",
// margin: "auto"
// }}
// ></div>
// </div>
// );
function onShown() {
console.log('diagram shown');
}
@ -37,95 +184,14 @@ function App(props) {
console.log('failed to show diagram');
}
// return (
// <ReactBpmn
// url={process.env.PUBLIC_URL + '/sample.bpmn'}
// onShown={ onShown }
// onLoading={ onLoading }
// onError={ onError }
// />
// );
//
const bpmnModeler = new BpmnModeler({
container: '#canvas',
propertiesPanel: {
parent: '#properties'
},
additionalModules: [
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule
]
});
async function exportDiagram() {
try {
var data = await bpmnModeler.saveXML({ format: true });
//POST request with body equal on data in JSON format
fetch("/admin/process-models/{{ process_model.id }}/save/{{ file_name }}", {
method: "POST",
headers: {
"Content-Type": "text/xml",
},
body: data.xml,
})
.then((response) => response.json())
//Then with the data from the response in JSON...
.then((data) => {
console.log("Success:", data);
})
//Then with the error genereted...
.catch((error) => {
console.error("Error:", error);
});
alert("Diagram exported. Check the developer tools!");
} catch (err) {
console.error("could not save BPMN 2.0 diagram", err);
}
}
/**
* Open diagram in our modeler instance.
*
* @param {String} bpmnXML diagram to display
*/
async function openDiagram(bpmnXML) {
// import diagram
try {
await bpmnModeler.importXML(bpmnXML);
// access modeler components
var canvas = bpmnModeler.get("canvas");
var overlays = bpmnModeler.get("overlays");
// zoom to fit full viewport
canvas.zoom("fit-viewport");
// attach an overlay to a node
overlays.add("SCAN_OK", "note", {
position: {
bottom: 0,
right: 0,
},
html: '<div class="diagram-note">Mixed up the labels?</div>',
});
// add marker
canvas.addMarker("SCAN_OK", "needs-discussion");
} catch (err) {
console.error("could not import BPMN 2.0 diagram", err);
}
}
// trying to use the python variable bpmn_xml directly causes the xml to have escape sequences
// and using the meta tag seems to help with that
// var bpmn_xml = $("#bpmn_xml").data();
openDiagram({process.env.PUBLIC_URL + '/sample.bpmn'});
// wire save button
$("#save-button").click(exportDiagram);
return (
<ReactEditor
url={process.env.PUBLIC_URL + '/sample.bpmn'}
onShown={ onShown }
onLoading={ onLoading }
onError={ onError }
/>
);
}
export default App;

View File

@ -0,0 +1,101 @@
* {
box-sizing: border-box;
}
body,
html {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 12px;
height: 100%;
max-height: 100%;
padding: 0;
margin: 0;
}
#js-properties-panel {
width: 400px;
}
a:link {
text-decoration: none;
}
.content {
position: relative;
width: 100%;
height: 100%;
display: flex;
}
.content > .message {
width: 100%;
height: 100%;
text-align: center;
display: table;
font-size: 16px;
color: #111;
}
.content > .message .note {
vertical-align: middle;
text-align: center;
display: table-cell;
}
.content > .message.error .details {
max-width: 500px;
font-size: 12px;
margin: 20px auto;
text-align: left;
color: #BD2828;
}
.content > .message.error pre {
border: solid 1px #BD2828;
background: #fefafa;
padding: 10px;
color: #BD2828;
}
.content:not(.with-error) .error,
.content.with-error .intro,
.content.with-diagram .intro {
display: none;
}
.content .canvas {
width: 100%;
}
.content .canvas,
.content .properties-panel-parent {
display: none;
}
.content.with-diagram .canvas,
.content.with-diagram .properties-panel-parent {
display: block;
}
.buttons {
position: fixed;
bottom: 20px;
left: 20px;
padding: 0;
margin: 0;
list-style: none;
}
.buttons > li {
display: inline-block;
margin-right: 10px;
}
.buttons > li > a {
background: #DDD;
border: solid 1px #666;
display: inline-block;
padding: 5px;
}
.buttons a {
opacity: 0.3;
}
.buttons a.active {
opacity: 1;
}
.properties-panel-parent {
border-left: 1px solid #ccc;
overflow: auto;
}
.properties-panel-parent:empty {
display: none;
}
.properties-panel-parent > .djs-properties-panel {
padding-bottom: 70px;
min-height: 100%;
}

143
src/react_editor.js Normal file
View File

@ -0,0 +1,143 @@
import BpmnModeler from 'bpmn-js/lib/Modeler';
import {
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule,
} from 'bpmn-js-properties-panel';
import React from "react";
import "bpmn-js-properties-panel/dist/assets/properties-panel.css"
import './bpmn-js-properties-panel.css';
export default class ReactEditor extends React.Component {
constructor(props) {
super(props);
this.state = { };
this.containerRef = React.createRef();
}
componentDidMount() {
const {
url,
diagramXML
} = this.props;
const container = this.containerRef.current;
this.bpmnViewer = new BpmnModeler({
container: container,
keyboard: {
bindTo: document
},
propertiesPanel: {
parent: '#js-properties-panel'
},
additionalModules: [
BpmnPropertiesPanelModule,
BpmnPropertiesProviderModule
]
});
this.bpmnViewer.on('import.done', (event) => {
const {
error,
warnings
} = event;
if (error) {
return this.handleError(error);
}
this.bpmnViewer.get('canvas').zoom('fit-viewport');
return this.handleShown(warnings);
});
if (url) {
return this.fetchDiagram(url);
}
if (diagramXML) {
return this.displayDiagram(diagramXML);
}
}
componentWillUnmount() {
this.bpmnViewer.destroy();
}
componentDidUpdate(prevProps, prevState) {
const {
props,
state
} = this;
if (props.url !== prevProps.url) {
return this.fetchDiagram(props.url);
}
const currentXML = props.diagramXML || state.diagramXML;
const previousXML = prevProps.diagramXML || prevState.diagramXML;
if (currentXML && currentXML !== previousXML) {
return this.displayDiagram(currentXML);
}
}
displayDiagram(diagramXML) {
this.bpmnViewer.importXML(diagramXML);
}
fetchDiagram(url) {
this.handleLoading();
fetch(url)
.then(response => response.text())
.then(text => this.setState({ diagramXML: text }))
.catch(err => this.handleError(err));
}
handleLoading() {
const { onLoading } = this.props;
if (onLoading) {
onLoading();
}
}
handleError(err) {
const { onError } = this.props;
if (onError) {
onError(err);
}
}
handleShown(warnings) {
const { onShown } = this.props;
if (onShown) {
onShown(warnings);
}
}
render() {
return (
<div className="content with-diagram" id="js-drop-zone">
<div className="canvas" id="js-canvas" ref={ this.containerRef }
style={{
border: "1px solid #000000",
height: "90vh",
width: "90vw",
margin: "auto"
}}
></div>
<div className="properties-panel-parent" id="js-properties-panel"></div>
</div>
);
}
}