add framework for blocking user interaction
[clamp.git] / ui-react / src / components / loop_viewer / svg / SvgGenerator.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END============================================
19  * ===================================================================
20  *
21  */
22
23 import React from 'react'
24 import styled from 'styled-components';
25 import { withRouter } from "react-router-dom";
26 import LoopCache from '../../../api/LoopCache';
27 import OnapConstant from '../../../utils/OnapConstants';
28
29 const DivStyled = styled.div`
30         overflow-x: scroll;
31     width: 100%;
32     height: 100%;
33 `
34
35 const emptySvg = (<svg> <text x="20" y="40">No LOOP (SVG)</text> </svg>);
36
37 class SvgGenerator extends React.Component {
38     boxWidth = 200;
39     boxHeight = 100;
40     boxSpace = 50;
41
42     static GENERATED_FROM_INSTANCE = "INSTANCE";
43     static GENERATED_FROM_TEMPLATE = "TEMPLATE";
44
45         state = {
46                 loopCache: new LoopCache({}),
47                 clickable: false,
48                 generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE
49         }
50
51         constructor(props) {
52                 super(props);
53                 this.state.loopCache = props.loopCache;
54                 this.state.clickable = props.clickable;
55                 this.state.generatedFrom = props.generatedFrom;
56                 this.handleSvgClick = this.handleSvgClick.bind(this);
57                 this.renderSvg = this.renderSvg.bind(this);
58         }
59
60         shouldComponentUpdate(nextProps, nextState) {
61                 return this.state.loopCache !== nextState.loopCache;
62         }
63
64         componentWillReceiveProps(newProps) {
65                 if (this.state.loopCache !== newProps.loopCache) {
66                         this.setState({
67                                 loopCache: newProps.loopCache,
68                         });
69                 }
70         }
71
72         handleSvgClick(event) {
73                 console.debug("svg click event received");
74                 if (this.state.clickable) {
75                         var elementName = event.target.parentNode.getAttribute('policyId');
76                         console.info("SVG element clicked", elementName);
77                         // Only allow movement to policy editing IF there busyLoadingCOunt is 0,
78                         // meaning we are not waiting for refreshStatus to complete, for example
79                         if (elementName !== null && !this.props.isBusyLoading()) {
80                                 this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName);
81                         }
82                 }
83         }
84
85     createVesBox (xPos) {
86         return this.createOneBox(xPos,null,null,'VES Collector','VES',null);
87     }
88
89     createOneArrow(xPos) {
90         return (
91          <svg width={this.boxSpace} height={this.boxHeight} x={xPos}>
92            <defs>
93                         <marker viewBox="0 0 20 20" markerWidth="20" markerHeight="20" orient="auto" refX="8.5" refY="5" id="arrow">
94                                 <path d="m 1 5 l 0 -3 l 7 3 l -7 3 z"
95                                         stroke-width= "1" stroke-linecap= "butt" stroke-dasharray= "10000, 1"
96                                         fill="#000000" stroke="#000000" />
97                         </marker>
98            </defs>
99            <line x1="0" y1="50%" x2="100%" y2="50%" stroke-width="2" color="black" stroke="black" marker-end="url(#arrow)"/>
100          </svg>
101         );
102     }
103
104     createBeginCircle(xPos, text) {
105             return (
106             <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
107                 <circle cx={this.boxWidth-30} cy="50%" r="30" stroke-width="1" color="black" stroke="black" fill="#27ae60"/>
108                 <text x={this.boxWidth-30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
109             </svg>
110             );
111     }
112
113     createEndCircle(xPos, text) {
114             return (
115             <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
116                 <circle cx={30} cy="50%" r="30" stroke-width="2" color="black" stroke="black" fill="#27ae60"/>
117                 <text x={30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
118             </svg>
119             );
120     }
121
122     createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) {
123         return (
124         <svg width={this.boxWidth} height={this.boxHeight} x={xPos} title="test">
125             <g policyId={policyId} loopElementModelId={loopElementModelId} policyType={policyType}>
126                 <rect width="100%" height="100%" stroke-width="2" color="black" stroke="black" fill="#1abc9c"/>
127                 <text x="50%" y="15%" color="white" fill="white" dominant-baseline="middle" text-anchor="middle" textLength="50%" lengthAdjust="spacingAndGlyphs">{title}</text>
128                 <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" textLength="80%" lengthAdjust="spacingAndGlyphs" >{name}</text>
129                 <text x="50%" y="80%" text-anchor="middle" dominant-baseline="middle" textLength="110%" lengthAdjust="spacingAndGlyphs" >{policyId}</text>
130             </g>
131         </svg>
132         );
133     }
134
135     createSvgFromTemplate() {
136         const allElements = [];
137         var xPos = 0;
138
139         allElements.push(this.createBeginCircle(xPos,"Start"))
140         xPos+=(this.boxWidth+this.boxSpace);
141
142         allElements.push(this.createOneArrow(xPos-this.boxSpace));
143
144         allElements.push(this.createVesBox(xPos));
145         xPos+=(this.boxWidth+this.boxSpace);
146
147         allElements.push(this.createOneArrow(xPos-this.boxSpace));
148         //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType)
149         for (var loopElement of this.state.loopCache.getAllLoopElementModels()) {
150
151             allElements.push(this.createOneBox(xPos,
152                 loopElement['name'],
153                 loopElement['name'],
154                 loopElement['shortName'],
155                 loopElement['loopElementType'],
156                 loopElement['loopElementType']))
157             xPos+=(this.boxWidth+this.boxSpace);
158             allElements.push(this.createOneArrow(xPos-this.boxSpace));
159         }
160
161         allElements.push(this.createEndCircle(xPos, "End"))
162         xPos+=(this.boxWidth+this.boxSpace);
163
164         return allElements;
165     }
166
167     createSvgFromInstance() {
168         const allElements = [];
169         var xPos = 0;
170
171         allElements.push(this.createBeginCircle(xPos,"Start"))
172         xPos+=(this.boxWidth+this.boxSpace);
173
174         allElements.push(this.createOneArrow(xPos-this.boxSpace));
175
176         allElements.push(this.createVesBox(xPos));
177         xPos+=(this.boxWidth+this.boxSpace);
178
179         allElements.push(this.createOneArrow(xPos-this.boxSpace));
180
181         for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) {
182             var loopElementModelName =  this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel'];
183             if (loopElementModelName !== undefined) {
184                 loopElementModelName = loopElementModelName['name'];
185             }
186             allElements.push(this.createOneBox(xPos,
187                 this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'],
188                 loopElementModelName,
189                 this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'],
190                 'microservice',
191                 OnapConstant.microServiceType))
192             xPos+=(this.boxWidth+this.boxSpace);
193             allElements.push(this.createOneArrow(xPos-this.boxSpace));
194         }
195
196         for (var opPolicy in this.state.loopCache.getOperationalPolicies()) {
197             loopElementModelName =  this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel'];
198             if (loopElementModelName !== undefined) {
199                 loopElementModelName = loopElementModelName['name'];
200             }
201             allElements.push(this.createOneBox(xPos,
202                 this.state.loopCache.getOperationalPolicies()[opPolicy]['name'],
203                 loopElementModelName,
204                 this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'],
205                 'operational',
206                 OnapConstant.operationalPolicyType))
207             xPos+=(this.boxWidth+this.boxSpace);
208             allElements.push(this.createOneArrow(xPos-this.boxSpace));
209         }
210
211         allElements.push(this.createEndCircle(xPos, "End"))
212         xPos+=(this.boxWidth+this.boxSpace);
213
214         return allElements;
215     }
216
217     renderSvg() {
218         if (this.state.loopCache.getLoopName() === undefined) {
219             return [emptySvg];
220         }
221         if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) {
222             return this.createSvgFromInstance();
223         } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) {
224             return this.createSvgFromTemplate();
225         }
226     }
227
228     render() {
229         var allTheElements = this.renderSvg();
230         var svgWidth = this.boxWidth*allTheElements.length;
231         var svgHeight = this.boxHeight+100;
232         return (
233             <DivStyled onClick={this.handleSvgClick} >
234                 <svg height={svgHeight} width={svgWidth}  preserveAspectRatio="none">
235                     {allTheElements}
236                 </svg>
237             </DivStyled>
238         );
239     }
240 }
241
242 export default withRouter(SvgGenerator);