block re-use of existing loop name; support derivation of SvgGenerator
[clamp.git] / ui-react / src / components / dialogs / Loop / CreateLoopModal.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2020 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 Select from 'react-select';
25 import Button from 'react-bootstrap/Button';
26 import Modal from 'react-bootstrap/Modal';
27 import Form from 'react-bootstrap/Form';
28 import Row from 'react-bootstrap/Row';
29 import Col from 'react-bootstrap/Col';
30 import styled from 'styled-components';
31 import LoopService from '../../../api/LoopService';
32 import TemplateService from '../../../api/TemplateService';
33 import LoopCache from '../../../api/LoopCache';
34 import SvgGenerator from '../../loop_viewer/svg/SvgGenerator';
35
36 const ModalStyled = styled(Modal)`
37         background-color: transparent;
38 `
39
40 const ErrMsgStyled = styled.div`
41         color: red;
42 `
43
44 export default class CreateLoopModal extends React.Component {
45         constructor(props, context) {
46                 super(props, context);
47
48                 this.getAllLoopTemplates = this.getAllLoopTemplates.bind(this);
49                 this.handleCreate = this.handleCreate.bind(this);
50                 this.handleModelName = this.handleModelName.bind(this);
51                 this.handleClose = this.handleClose.bind(this);
52                 this.handleDropDownListChange = this.handleDropDownListChange.bind(this);
53                 this.renderSvg = this.renderSvg.bind(this);
54                 this.state = {
55                         show: true,
56                         chosenTemplateName: '',
57                         modelInputErrMsg: '',
58                         modelName: '',
59                         templateNames: [],
60                         fakeLoopCacheWithTemplate: new LoopCache({})
61                 };
62         }
63
64         async componentDidMount() {
65                 await this.getAllLoopTemplates();
66                 await this.getModelNames();
67         }
68
69         handleClose() {
70                 this.setState({ show: false });
71                 this.props.history.push('/');
72         }
73
74         handleDropDownListChange(e) {
75             if (typeof e.value !== "undefined") {
76                 this.setState({
77                 fakeLoopCacheWithTemplate:
78                 new LoopCache({
79                     "loopTemplate":e.templateObject,
80                     "name": "fakeLoop"
81                 }),
82                 chosenTemplateName: e.value
83                 })
84                 } else {
85                 this.setState({ fakeLoopCacheWithTemplate: new LoopCache({}) })
86         }
87         }
88
89         getAllLoopTemplates() {
90                 TemplateService.getAllLoopTemplates().then(templatesData => {
91                     const templateOptions = templatesData.map((templateData) => { return { label: templateData.name, value: templateData.name, templateObject: templateData } });
92             this.setState({
93                 templateNames: templateOptions })
94                 });
95         }
96
97         getModelNames() {
98                 TemplateService.getLoopNames().then(loopNames => {
99                         if (!loopNames) {
100                                 loopNames = [];
101                         }
102                         // Remove LOOP_ prefix
103                         let trimmedLoopNames = loopNames.map(str => str.replace('LOOP_', ''));
104                         this.setState({ modelNames: trimmedLoopNames });
105                 });
106         }
107
108         handleCreate() {
109                 if (!this.state.modelName) {
110                         alert("A model name is required");
111                         return;
112                 }
113                 console.debug("Create Model " + this.state.modelName + ", Template " + this.state.chosenTemplateName + " is chosen");
114                 this.setState({ show: false });
115                 LoopService.createLoop("LOOP_" + this.state.modelName, this.state.chosenTemplateName).then(text => {
116                         console.debug("CreateLoop response received: ", text);
117                         try {
118                                 this.props.history.push('/');
119                                 this.props.loadLoopFunction("LOOP_" + this.state.modelName);
120                         } catch(err) {
121                                 alert(text);
122                                 this.props.history.push('/');
123                         }
124                 })
125                 .catch(error => {
126                         console.debug("Create Loop failed");
127                 });
128         }
129
130         handleModelName(event) {
131                 if (this.state.modelNames.includes(event.target.value)) {
132                         this.setState({
133                                 modelInputErrMsg: 'A model named "' + event.target.value + '" already exists. Please pick another name.',
134                                 modelName: event.target.value
135                         });
136                         return;
137                 } else {
138                         this.setState({
139                                 modelInputErrMsg: '',
140                                 modelName: event.target.value
141                         });
142                 }
143         }
144
145         renderSvg() {
146                 return (
147                         <SvgGenerator loopCache={this.state.fakeLoopCacheWithTemplate} clickable={false} generatedFrom={SvgGenerator.GENERATED_FROM_TEMPLATE}/>
148                 );
149         }
150
151         render() {
152                 return (
153                         <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
154                                 <Modal.Header closeButton>
155                                         <Modal.Title>Create Model</Modal.Title>
156                                 </Modal.Header>
157                                 <Modal.Body>
158                                         <Form.Group as={Row} controlId="formPlaintextEmail">
159                                                 <Form.Label column sm="2">Template Name:</Form.Label>
160                                                 <Col sm="10">
161                                                         <Select onChange={this.handleDropDownListChange} options={this.state.templateNames} />
162                                                 </Col>
163                                         </Form.Group>
164                     <Form.Group as={Row} style={{alignItems: 'center'}} controlId="formSvgPreview">
165                     <Form.Label column sm="2">Model Preview:</Form.Label>
166                         <Col sm="10">
167                             {this.renderSvg()}
168                         </Col>
169                     </Form.Group>
170                                         <Form.Group as={Row} controlId="formPlaintextEmail">
171                                                 <Form.Label column sm="2">Model Name:</Form.Label>
172                                                 <input sm="5" type="text" style={{width: '50%', marginLeft: '1em' }}
173                                                         value={this.state.modelName}
174                                                         onChange={this.handleModelName}
175                                                 />
176                                                 <span sm="5"/>
177                                         </Form.Group>
178                                         <Form.Group as={Row} controlId="formPlaintextEmail">
179                                                 <Form.Label column sm="2"> </Form.Label>
180                                                 <ErrMsgStyled>{this.state.modelInputErrMsg}</ErrMsgStyled>
181                                         </Form.Group>
182                                 </Modal.Body>
183                                 <Modal.Footer>
184                                         <Button variant="secondary" type="null" onClick={this.handleClose}>Cancel</Button>
185                                         <Button variant="primary" type="submit" onClick={this.handleCreate}>Create</Button>
186                                 </Modal.Footer>
187                         </ModalStyled>
188                 );
189         }
190 }