mirror of
https://github.com/sartography/spiffworkflow-frontend.git
synced 2025-02-23 03:38:13 +00:00
we can edit a bpmn diagram now w/ burnettk
This commit is contained in:
parent
945d6e85b4
commit
7b52804639
44
package-lock.json
generated
44
package-lock.json
generated
@ -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",
|
||||
|
@ -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",
|
||||
|
258
src/App.js
258
src/App.js
@ -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;
|
||||
|
101
src/bpmn-js-properties-panel.css
Normal file
101
src/bpmn-js-properties-panel.css
Normal 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
143
src/react_editor.js
Normal 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>
|
||||
);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user