block re-use of existing loop name; support derivation of SvgGenerator
[clamp.git] / ui-react / src / LoopUI.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights
6  *                             reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END============================================
20  * ===================================================================
21  *
22  */
23
24 import React from 'react';
25 import styled from 'styled-components';
26 import MenuBar from './components/menu/MenuBar';
27 import Navbar from 'react-bootstrap/Navbar';
28 import logo from './logo.png';
29 import { GlobalClampStyle } from './theme/globalStyle.js';
30 import OnapConstants from './utils/OnapConstants';
31
32 import SvgGenerator from './components/loop_viewer/svg/SvgGenerator';
33 import LoopLogs from './components/loop_viewer/logs/LoopLogs';
34 import LoopStatus from './components/loop_viewer/status/LoopStatus';
35 import UserService from './api/UserService';
36 import LoopCache from './api/LoopCache';
37 import LoopActionService from './api/LoopActionService';
38
39 import { Route } from 'react-router-dom'
40 import CreateLoopModal from './components/dialogs/Loop/CreateLoopModal';
41 import OpenLoopModal from './components/dialogs/Loop/OpenLoopModal';
42 import ModifyLoopModal from './components/dialogs/Loop/ModifyLoopModal';
43 import PolicyModal from './components/dialogs/Policy/PolicyModal';
44 import LoopPropertiesModal from './components/dialogs/Loop/LoopPropertiesModal';
45 import UserInfoModal from './components/dialogs/UserInfoModal';
46 import LoopService from './api/LoopService';
47 import UploadToscaPolicyModal from './components/dialogs/Tosca/UploadToscaPolicyModal';
48 import ViewToscaPolicyModal from './components/dialogs/Tosca/ViewToscaPolicyModal';
49 import ViewLoopTemplatesModal from './components/dialogs/Tosca/ViewLoopTemplatesModal';
50 import ManageDictionaries from './components/dialogs/ManageDictionaries/ManageDictionaries';
51 import PerformAction from './components/dialogs/PerformActions';
52 import RefreshStatus from './components/dialogs/RefreshStatus';
53 import DeployLoopModal from './components/dialogs/Loop/DeployLoopModal';
54 import Alert from 'react-bootstrap/Alert';
55 import Spinner from 'react-bootstrap/Spinner';
56
57 import { Link } from 'react-router-dom';
58
59 const StyledMainDiv = styled.div`
60         background-color: ${props => props.theme.backgroundColor};
61 `
62
63 const StyledSpinnerDiv = styled.div`
64         justify-content: center !important;
65         display: flex !important;
66 `;
67
68 const ProjectNameStyled = styled.a`
69         vertical-align: middle;
70         padding-left: 30px;
71         font-size: 36px;
72         font-weight: bold;
73 `
74
75 const StyledRouterLink = styled(Link)`
76         color: ${props => props.theme.menuFontColor};
77         background-color: ${props => props.theme.backgroundColor};
78 `
79
80 const StyledLoginInfo = styled.a`
81         color: ${props => props.theme.menuFontColor};
82         background-color: ${props => props.theme.backgroundColor};
83 `
84
85 const LoopViewDivStyled = styled.div`
86         height: 100%;
87         overflow: hidden;
88         margin-left: 10px;
89         margin-right: 10px;
90         margin-bottom: 10px;
91         color: ${props => props.theme.loopViewerFontColor};
92         background-color: ${props => props.theme.loopViewerBackgroundColor};
93         border: 1px solid transparent;
94         border-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
95 `
96
97 const LoopViewHeaderDivStyled = styled.div`
98         background-color: ${props => props.theme.loopViewerHeaderBackgroundColor};
99         padding: 10px 10px;
100         color: ${props => props.theme.loopViewerHeaderFontColor};
101 `
102
103 const LoopViewBodyDivStyled = styled.div`
104         background-color: ${props => (props.theme.loopViewerBackgroundColor)};
105         padding: 10px 10px;
106         color: ${props => (props.theme.loopViewerHeaderFontColor)};
107         height: 95%;
108 `
109
110 export default class LoopUI extends React.Component {
111
112         state = {
113                 userName: null,
114                 loopName: OnapConstants.defaultLoopName,
115                 loopCache: new LoopCache({}),
116                 showSucAlert: false,
117                 showFailAlert: false,
118                 busyLoadingCount: 0
119         };
120
121         constructor() {
122                 super();
123                 this.getUser = this.getUser.bind(this);
124                 this.updateLoopCache = this.updateLoopCache.bind(this);
125                 this.loadLoop = this.loadLoop.bind(this);
126                 this.closeLoop = this.closeLoop.bind(this);
127                 this.showSucAlert =  this.showSucAlert.bind(this);
128                 this.showFailAlert =  this.showFailAlert.bind(this);
129                 this.disableAlert =  this.disableAlert.bind(this);
130                 this.setBusyLoading = this.setBusyLoading.bind(this);
131                 this.clearBusyLoading = this.clearBusyLoading.bind(this);
132                 this.isBusyLoading = this.isBusyLoading.bind(this);
133                 this.renderGlobalStyle = this.renderGlobalStyle.bind(this);
134                 this.renderSvg = this.renderSvg.bind(this);
135         }
136
137         componentWillMount() {
138                 this.getUser();
139         }
140
141         getUser() {
142                 UserService.login().then(user => {
143                         this.setState({ userName: user })
144                 });
145         }
146
147         renderMenuNavBar() {
148                 return (
149                         <MenuBar loopName={this.state.loopName}/>
150                 );
151         }
152
153         renderUserLoggedNavBar() {
154                 return (
155                         <Navbar.Text>
156                         <StyledLoginInfo>Signed in as: </StyledLoginInfo>
157                                 <StyledRouterLink to="/userInfo">{this.state.userName}</StyledRouterLink>
158                         </Navbar.Text>
159                 );
160         }
161
162         renderLogoNavBar() {
163                 return (
164                         <Navbar.Brand>
165                                 <img height="50px" width="234px" src={logo} alt="" />
166                                 <ProjectNameStyled>CLAMP</ProjectNameStyled>
167                         </Navbar.Brand>
168                 );
169         }
170
171         renderAlertBar() {
172                 return (
173                         <div>
174                                 <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
175                                         {this.state.showMessage}
176                                 </Alert>
177                                 <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
178                                         {this.state.showMessage}
179                                 </Alert>
180                         </div>
181                 );
182         }
183
184         renderNavBar() {
185                 return (
186                         <Navbar >
187                                 {this.renderLogoNavBar()}
188                                 <Navbar.Toggle aria-controls="responsive-navbar-nav" />
189                                 {this.renderMenuNavBar()}
190                                 {this.renderUserLoggedNavBar()}
191                         </Navbar>
192                 );
193         }
194
195         renderLoopViewHeader() {
196                 return (
197                         <LoopViewHeaderDivStyled>
198                                 Loop Viewer - {this.state.loopName} - ({this.state.loopCache.getTemplateName()})
199                         </LoopViewHeaderDivStyled>
200                 );
201         }
202
203         renderSvg() {
204                 return (
205                         <SvgGenerator loopCache={this.state.loopCache} clickable={true} generatedFrom={SvgGenerator.GENERATED_FROM_INSTANCE} isBusyLoading={this.isBusyLoading}/>
206                 )
207         }
208         renderLoopViewBody() {
209                 return (
210                         <LoopViewBodyDivStyled>
211                                 {this.renderSvg()}
212                                 <LoopStatus loopCache={this.state.loopCache}/>
213                                 <LoopLogs loopCache={this.state.loopCache} />
214                         </LoopViewBodyDivStyled>
215                 );
216         }
217
218         getLoopCache() {
219                 return this.state.loopCache;
220
221         }
222
223         renderLoopViewer() {
224                 return (
225                         <LoopViewDivStyled>
226                                 {this.renderLoopViewHeader()}
227                                 {this.renderLoopViewBody()}
228                         </LoopViewDivStyled>
229                 );
230         }
231
232         updateLoopCache(loopJson) {
233
234                 // If call with an empty object for loopJson, this is a reset to empty
235                 // from someplace like PerformActions for the case where we are "deleting"
236                 // a Control Loop model. Set the loopName to the default.
237
238                 if (loopJson === null) {
239                         this.setState({ loopName: OnapConstants.defaultLoopName });
240                         this.setState({ loopCache: new LoopCache({}) });
241                 } else {
242                         this.setState({ loopCache: new LoopCache(loopJson) });
243                         this.setState({ loopName: this.state.loopCache.getLoopName() });
244                 }
245                 console.info(this.state.loopName+" loop loaded successfully");
246         }
247
248         showSucAlert(message) {
249                 this.setState ({ showSucAlert: true, showMessage:message });
250         }
251
252         showFailAlert(message) {
253                 this.setState ({ showFailAlert: true, showMessage:message });
254         }
255
256         disableAlert() {
257                 this.setState ({ showSucAlert: false, showFailAlert: false });
258         }
259
260         loadLoop(loopName) {
261                 this.setBusyLoading();
262                 LoopService.getLoop(loopName).then(loop => {
263                         console.debug("Updating loopCache");
264                         LoopActionService.refreshStatus(loopName).then(data => {
265                                 this.updateLoopCache(data);
266                                 this.clearBusyLoading();
267                                 this.props.history.push('/');
268                         })
269                         .catch(error => {
270                                 this.updateLoopCache(loop);
271                                 this.clearBusyLoading();
272                                 this.props.history.push('/');
273                         });
274                 });
275         }
276
277         setBusyLoading() {
278                 this.setState((state,props) => ({ busyLoadingCount: ++state.busyLoadingCount }));
279         }
280
281         clearBusyLoading() {
282                 this.setState((state,props) => ({ busyLoadingCount: --state.busyLoadingCount }));
283         }
284
285         isBusyLoading() {
286                 if (this.state.busyLoadingCount === 0) {
287                         return false;
288                 } else {
289                         return true;
290                 }
291         }
292
293         closeLoop() {
294                 this.setState({ loopCache: new LoopCache({}), loopName: OnapConstants.defaultLoopName });
295                 this.props.history.push('/');
296         }
297
298         renderRoutes() {
299                 return(
300                         <React.Fragment>
301                                 <Route path="/uploadToscaPolicyModal" render={(routeProps) => (<UploadToscaPolicyModal {...routeProps} />)} />
302                                 <Route path="/viewToscaPolicyModal" render={(routeProps) => (<ViewToscaPolicyModal {...routeProps} />)} />
303                                 <Route path="/ViewLoopTemplatesModal" render={(routeProps) => (<ViewLoopTemplatesModal {...routeProps} />)} />
304                                 <Route path="/ManageDictionaries" render={(routeProps) => (<ManageDictionaries {...routeProps} />)} />
305
306                                 <Route path="/policyModal/:policyInstanceType/:policyName" render={(routeProps) => (<PolicyModal {...routeProps}
307                                         loopCache={this.getLoopCache()}
308                                         loadLoopFunction={this.loadLoop}/>)}
309                                 />
310                                 <Route path="/createLoop" render={(routeProps) => (<CreateLoopModal {...routeProps}
311                                         loadLoopFunction={this.loadLoop} />)}
312                                 />
313                                 <Route path="/openLoop" render={(routeProps) => (<OpenLoopModal {...routeProps}
314                                         loadLoopFunction={this.loadLoop} />)}
315                                 />
316                                 <Route path="/loopProperties" render={(routeProps) => (<LoopPropertiesModal {...routeProps}
317                                         loopCache={this.getLoopCache()}
318                                         loadLoopFunction={this.loadLoop}/>)}
319                                 />
320                                 <Route path="/modifyLoop" render={(routeProps) => (<ModifyLoopModal {...routeProps}
321                                         loopCache={this.getLoopCache()}
322                                         loadLoopFunction={this.loadLoop}/>)}
323                                 />
324
325                                 <Route path="/userInfo" render={(routeProps) => (<UserInfoModal {...routeProps} />)} />
326                                 <Route path="/closeLoop" render={this.closeLoop} />
327
328                                 <Route path="/submit" render={(routeProps) => (<PerformAction {...routeProps}
329                                         loopAction="submit"
330                                         loopCache={this.getLoopCache()}
331                                         updateLoopFunction={this.updateLoopCache}
332                                         showSucAlert={this.showSucAlert}
333                                         showFailAlert={this.showFailAlert}
334                                         setBusyLoading={this.setBusyLoading}
335                                         clearBusyLoading={this.clearBusyLoading}/>)}
336                                 />
337                                 <Route path="/stop" render={(routeProps) => (<PerformAction {...routeProps}
338                                         loopAction="stop"
339                                         loopCache={this.getLoopCache()}
340                                         updateLoopFunction={this.updateLoopCache}
341                                         showSucAlert={this.showSucAlert}
342                                         showFailAlert={this.showFailAlert}
343                                         setBusyLoading={this.setBusyLoading}
344                                         clearBusyLoading={this.clearBusyLoading}/>)}
345                                 />
346                                 <Route path="/restart" render={(routeProps) => (<PerformAction {...routeProps}
347                                         loopAction="restart"
348                                         loopCache={this.getLoopCache()}
349                                         updateLoopFunction={this.updateLoopCache}
350                                         showSucAlert={this.showSucAlert}
351                                         showFailAlert={this.showFailAlert}
352                                         setBusyLoading={this.setBusyLoading}
353                                         clearBusyLoading={this.clearBusyLoading}/>)}
354                                 />
355                                 <Route path="/delete" render={(routeProps) => (<PerformAction {...routeProps}
356                                         loopAction="delete"
357                                         loopCache={this.getLoopCache()}
358                                         updateLoopFunction={this.updateLoopCache}
359                                         showSucAlert={this.showSucAlert}
360                                         showFailAlert={this.showFailAlert}
361                                         setBusyLoading={this.setBusyLoading}
362                                         clearBusyLoading={this.clearBusyLoading}/>)}
363                                 />
364                                 <Route path="/undeploy" render={(routeProps) => (<PerformAction {...routeProps}
365                                         loopAction="undeploy"
366                                         loopCache={this.getLoopCache()}
367                                         updateLoopFunction={this.updateLoopCache}
368                                         showSucAlert={this.showSucAlert}
369                                         showFailAlert={this.showFailAlert}
370                                         setBusyLoading={this.setBusyLoading}
371                                         clearBusyLoading={this.clearBusyLoading}/>)}
372                                 />
373                                 <Route path="/deploy" render={(routeProps) => (<DeployLoopModal {...routeProps}
374                                         loopCache={this.getLoopCache()}
375                                         updateLoopFunction={this.updateLoopCache}
376                                         showSucAlert={this.showSucAlert}
377                                         showFailAlert={this.showFailAlert}/>)}
378                                 />
379                                 <Route path="/refreshStatus" render={(routeProps) => (<RefreshStatus {...routeProps}
380                                         loopCache={this.getLoopCache()}
381                                         updateLoopFunction={this.updateLoopCache}
382                                         showSucAlert={this.showSucAlert}
383                                         showFailAlert={this.showFailAlert}/>)}
384                                 />
385                         </React.Fragment>
386                 );
387         }
388
389         renderGlobalStyle() {
390                 return (
391                         <GlobalClampStyle />
392                 );
393         };
394
395
396         renderSpinner() {
397                 if (this.isBusyLoading()) {
398                         return (
399                                 <StyledSpinnerDiv>
400                                         <Spinner animation="border" role="status">
401                                                 <span className="sr-only">Loading...</span>
402                                         </Spinner>
403                                 </StyledSpinnerDiv>
404                         );
405                 } else {
406                         return (<div></div>);
407                 }
408         }
409
410         render() {
411                 return (
412                                 <StyledMainDiv id="main_div">
413                                         {this.renderGlobalStyle()}
414                                         {this.renderRoutes()}
415                                         {this.renderSpinner()}
416                                         {this.renderAlertBar()}
417                                         {this.renderNavBar()}
418                                         {this.renderLoopViewer()}
419                                 </StyledMainDiv>
420                 );
421         }
422 }