Merge "Search Workflow by name BDD test"
[sdc/sdc-workflow-designer.git] / workflow-designer-ui / src / main / frontend / src / features / version / composition / CompositionView.js
1 /*
2 * Copyright © 2018 European Support Limited
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *http://www.apache.org/licenses/LICENSE-2.0
9 *
10  * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 import React, { Component } from 'react';
17 import fileSaver from 'file-saver';
18 import CustomModeler from './custom-modeler';
19 import propertiesPanelModule from 'bpmn-js-properties-panel';
20 import propertiesProviderModule from './custom-properties-provider/provider/camunda';
21 import camundaModuleDescriptor from './custom-properties-provider/descriptors/camunda';
22 import newDiagramXML from './newDiagram.bpmn';
23 import PropTypes from 'prop-types';
24 import CompositionButtons from './components/CompositionButtonsPanel';
25 import { setElementInputsOutputs } from './bpmnUtils.js';
26 import { I18n } from 'react-redux-i18n';
27
28 class CompositionView extends Component {
29     static propTypes = {
30         compositionUpdate: PropTypes.func,
31         showErrorModal: PropTypes.func,
32         composition: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
33         name: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
34         inputOutput: PropTypes.object,
35         activities: PropTypes.array
36     };
37     constructor() {
38         super();
39         this.generatedId = 'bpmn-container' + Date.now();
40         this.fileInput = React.createRef();
41         this.selectedElement = false;
42         this.state = {
43             diagram: false
44         };
45     }
46
47     componentDidMount() {
48         const { composition } = this.props;
49
50         this.modeler = new CustomModeler({
51             propertiesPanel: {
52                 parent: '#js-properties-panel'
53             },
54             additionalModules: [
55                 propertiesPanelModule,
56                 propertiesProviderModule
57             ],
58             moddleExtensions: {
59                 camunda: camundaModuleDescriptor
60             },
61             workflow: {
62                 activities: this.props.activities,
63                 onChange: this.onActivityChanged
64             }
65         });
66
67         this.modeler.attachTo('#' + this.generatedId);
68         this.setDiagramToBPMN(composition ? composition : newDiagramXML);
69         this.modeler.on('element.out', () => this.exportDiagramToStore());
70     }
71     onActivityChanged = async (bo, selectedValue) => {
72         const selectedActivity = this.props.activities.find(
73             el => el.name === selectedValue
74         );
75
76         if (selectedActivity) {
77             const inputsOutputs = {
78                 inputs: selectedActivity.inputs,
79                 outputs: selectedActivity.outputs
80             };
81             setElementInputsOutputs(
82                 bo,
83                 inputsOutputs,
84                 this.modeler.get('moddle')
85             );
86         }
87     };
88
89     setDiagramToBPMN = diagram => {
90         let modeler = this.modeler;
91         this.modeler.importXML(diagram, err => {
92             if (err) {
93                 return this.props.showErrorModal(
94                     I18n.t('workflow.composition.importErrorMsg')
95                 );
96             }
97             let canvas = modeler.get('canvas');
98             canvas.zoom('fit-viewport');
99             setElementInputsOutputs(
100                 canvas._rootElement.businessObject,
101                 this.props.inputOutput,
102                 this.modeler.get('moddle')
103             );
104         });
105     };
106
107     exportDiagramToStore = () => {
108         this.modeler.saveXML({ format: true }, (err, xml) => {
109             if (err) {
110                 return this.props.showErrorModal(
111                     I18n.t('workflow.composition.saveErrorMsg')
112                 );
113             }
114             return this.props.compositionUpdate(xml);
115         });
116     };
117
118     exportDiagram = () => {
119         const { name, showErrorModal } = this.props;
120         this.modeler.saveXML({ format: true }, (err, xml) => {
121             if (err) {
122                 return showErrorModal(
123                     I18n.t('workflow.composition.exportErrorMsg')
124                 );
125             }
126             const blob = new Blob([xml], { type: 'text/html;charset=utf-8' });
127             fileSaver.saveAs(blob, `${name}-diagram.bpmn`);
128         });
129     };
130
131     loadNewDiagram = () => {
132         this.setDiagramToBPMN(newDiagramXML);
133     };
134
135     uploadDiagram = () => {
136         this.fileInput.current.click();
137     };
138
139     handleFileInputChange = filesList => {
140         const file = filesList[0];
141         const reader = new FileReader();
142         reader.onloadend = event => {
143             var xml = event.target.result;
144             this.setDiagramToBPMN(xml);
145             this.fileInput.value = '';
146         };
147         reader.readAsText(file);
148     };
149
150     render() {
151         return (
152             <div className="composition-view content">
153                 <input
154                     ref={this.fileInput}
155                     onChange={e => this.handleFileInputChange(e.target.files)}
156                     id="file-input"
157                     accept=".bpmn, .xml"
158                     type="file"
159                     name="file-input"
160                     style={{ display: 'none' }}
161                 />
162                 <div
163                     onBlur={() => {
164                         this.exportDiagramToStore();
165                     }}
166                     className="bpmn-container"
167                     id={this.generatedId}
168                 />
169                 <div className="bpmn-sidebar">
170                     <div
171                         className="properties-panel"
172                         id="js-properties-panel"
173                     />
174                     <CompositionButtons
175                         onClean={this.loadNewDiagram}
176                         onDownload={this.exportDiagram}
177                         onUpload={this.uploadDiagram}
178                     />
179                 </div>
180             </div>
181         );
182     }
183 }
184
185 export default CompositionView;