d3b427396dca7603d3a962e559c000126074cb42
[clamp.git] / ui-react / src / components / dialogs / Policy / PolicyModal.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP CLAMP
4  * ================================================================================
5  * Copyright (C) 2020 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 Button from 'react-bootstrap/Button';
26 import Form from 'react-bootstrap/Form';
27 import Col from 'react-bootstrap/Col';
28 import Row from 'react-bootstrap/Row';
29 import Select from 'react-select';
30 import Modal from 'react-bootstrap/Modal';
31 import styled from 'styled-components';
32 import LoopService from '../../../api/LoopService';
33 import LoopCache from '../../../api/LoopCache';
34 import JSONEditor from '@json-editor/json-editor';
35 import Alert from 'react-bootstrap/Alert';
36 import OnapConstant from '../../../utils/OnapConstants';
37
38 const ModalStyled = styled(Modal)`
39         background-color: transparent;
40 `
41
42 export default class PolicyModal extends React.Component {
43
44         state = {
45                 show: true,
46                 loopCache: this.props.loopCache,
47                 jsonEditor: null,
48                 policyName: this.props.match.params.policyName,
49                 // This is to indicate whether it's an operational or config policy (in terms of loop instance)
50                 policyInstanceType: this.props.match.params.policyInstanceType,
51                 pdpGroup: null,
52                 pdpGroupList: [],
53                 pdpSubgroupList: [],
54                 chosenPdpGroup: '',
55                 chosenPdpSubgroup: '',
56                 showSucAlert: false,
57                 showFailAlert: false
58         };
59
60         constructor(props, context) {
61                 super(props, context);
62                 this.handleClose = this.handleClose.bind(this);
63                 this.handleSave = this.handleSave.bind(this);
64                 this.renderJsonEditor = this.renderJsonEditor.bind(this);
65                 this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
66                 this.handlePdpSubgroupChange = this.handlePdpSubgroupChange.bind(this);
67                 this.createJsonEditor = this.createJsonEditor.bind(this);
68                 this.handleRefresh = this.handleRefresh.bind(this);
69                 this.disableAlert =  this.disableAlert.bind(this);
70                 this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this);
71                 this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this);
72                 this.renderModalTitle = this.renderModalTitle.bind(this);
73         }
74
75         handleSave() {
76                 var errors = this.state.jsonEditor.validate();
77                 var editorData = this.state.jsonEditor.getValue();
78
79                 if (errors.length !== 0) {
80                         console.error("Errors detected during policy data validation ", errors);
81                         this.setState({
82                         showFailAlert: true,
83                         showMessage: "Errors detected during policy data validation " + errors
84             });
85                         return;
86                 }
87                 else {
88                         console.info("NO validation errors found in policy data");
89                         if (this.state.policyInstanceType === OnapConstant.microServiceType) {
90                 this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData);
91                 this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
92                 LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => {
93                     this.setState({ show: false });
94                     this.props.history.push('/');
95                     this.props.loadLoopFunction(this.state.loopCache.getLoopName());
96                 });
97                         } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
98                                 this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData);
99                                 this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
100                                 LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => {
101                                         this.setState({ show: false });
102                                 this.props.history.push('/');
103                                         this.props.loadLoopFunction(this.state.loopCache.getLoopName());
104                                 });
105                         }
106                 }
107         }
108
109         handleClose() {
110                 this.setState({ show: false });
111                 this.props.history.push('/');
112         }
113
114         componentDidMount() {
115                 this.renderJsonEditor();
116         }
117
118     createJsonEditor(toscaModel, editorData) {
119         JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
120                         getTab: function(text,tabId) {
121                                 var liel = document.createElement('li');
122                                 liel.classList.add('nav-item');
123                                 var ael = document.createElement("a");
124                                 ael.classList.add("nav-link");
125                                 ael.setAttribute("style",'padding:10px;max-width:160px;');
126                                 ael.setAttribute("href", "#" + tabId);
127                                 ael.setAttribute('data-toggle', 'tab');
128                                 text.setAttribute("style",'word-wrap:break-word;');
129                                 ael.appendChild(text);
130                                 liel.appendChild(ael);
131                                 return liel;
132                         }
133                 });
134         return new JSONEditor(document.getElementById("editor"),
135         {   schema: toscaModel,
136               startval: editorData,
137               theme: 'myBootstrap4',
138               object_layout: 'grid',
139               disable_properties: false,
140               disable_edit_json: false,
141               disable_array_reorder: true,
142               disable_array_delete_last_row: true,
143               disable_array_delete_all_rows: false,
144               array_controls_top: true,
145               keep_oneof_values: false,
146               collapsed:true,
147               show_errors: 'always',
148               display_required_only: false,
149               show_opt_in: false,
150               prompt_before_delete: true,
151               required_by_default: false
152         })
153     }
154
155         renderJsonEditor() {
156                 console.debug("Rendering PolicyModal ", this.state.policyName);
157                 var toscaModel = {};
158                 var editorData = {};
159                 var pdpGroupValues = {};
160                 var chosenPdpGroupValue, chosenPdpSubgroupValue;
161                 if (this.state.policyInstanceType === OnapConstant.microServiceType) {
162                         toscaModel = this.state.loopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
163                         editorData = this.state.loopCache.getMicroServicePropertiesForName(this.state.policyName);
164                         pdpGroupValues = this.state.loopCache.getMicroServiceSupportedPdpGroup(this.state.policyName);
165                         chosenPdpGroupValue = this.state.loopCache.getMicroServicePdpGroup(this.state.policyName);
166                         chosenPdpSubgroupValue = this.state.loopCache.getMicroServicePdpSubgroup(this.state.policyName);
167                 } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
168                         toscaModel = this.state.loopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
169                         editorData = this.state.loopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
170                         pdpGroupValues = this.state.loopCache.getOperationalPolicySupportedPdpGroup(this.state.policyName);
171                         chosenPdpGroupValue = this.state.loopCache.getOperationalPolicyPdpGroup(this.state.policyName);
172                         chosenPdpSubgroupValue = this.state.loopCache.getOperationalPolicyPdpSubgroup(this.state.policyName);
173                 }
174
175                 if (toscaModel == null) {
176                         return;
177                 }
178
179         var pdpSubgroupValues = [];
180                 if (typeof(chosenPdpGroupValue) !== "undefined") {
181                         var selectedPdpGroup =  pdpGroupValues.filter(entry => (Object.keys(entry)[0] === chosenPdpGroupValue));
182                         pdpSubgroupValues = selectedPdpGroup[0][chosenPdpGroupValue].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
183                 }
184                 this.setState({
185                                         jsonEditor: this.createJsonEditor(toscaModel,editorData),
186                                         pdpGroup: pdpGroupValues,
187                                         pdpGroupList: pdpGroupValues.map(entry => {
188                                                                 return { label: Object.keys(entry)[0], value: Object.keys(entry)[0] };
189                                                 }),
190                                         pdpSubgroupList: pdpSubgroupValues,
191                                         chosenPdpGroup: chosenPdpGroupValue,
192                                         chosenPdpSubgroup: chosenPdpSubgroupValue
193                                 })
194         }
195
196         handlePdpGroupChange(e) {
197                 var selectedPdpGroup =  this.state.pdpGroup.filter(entry => (Object.keys(entry)[0] === e.value));
198                 const pdpSubgroupValues = selectedPdpGroup[0][e.value].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
199                 if (this.state.chosenPdpGroup !== e.value) {
200                         this.setState({
201                                 chosenPdpGroup: e.value,
202                                 chosenPdpSubgroup: '',
203                                 pdpSubgroupList: pdpSubgroupValues
204                         });
205                 }
206         }
207
208         handlePdpSubgroupChange(e) {
209                 this.setState({ chosenPdpSubgroup: e.value });
210         }
211
212         handleRefresh() {
213                 var newLoopCache, toscaModel, editorData;
214                 if (this.state.policyInstanceType === OnapConstant.microServiceType) {
215                         LoopService.refreshMicroServicePolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
216                                 newLoopCache =  new LoopCache(data);
217                                 toscaModel = newLoopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
218                                 editorData = newLoopCache.getMicroServicePropertiesForName(this.state.policyName);
219                                 document.getElementById("editor").innerHTML = "";
220                                 this.setState({
221                                         loopCache: newLoopCache,
222                                         jsonEditor: this.createJsonEditor(toscaModel,editorData),
223                                         showSucAlert: true,
224                                         showMessage: "Successfully refreshed"
225                                 });
226                         })
227                         .catch(error => {
228                                 console.error("Error while refreshing the Operational Policy Json Representation");
229                                 this.setState({
230                                         showFailAlert: true,
231                                         showMessage: "Refreshing of UI failed"
232                                 });
233                         });
234                 } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
235                         LoopService.refreshOperationalPolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
236                                 var newLoopCache =  new LoopCache(data);
237                                 toscaModel = newLoopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
238                                 editorData = newLoopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
239                                 document.getElementById("editor").innerHTML = "";
240                                 this.setState({
241                                         loopCache: newLoopCache,
242                                         jsonEditor: this.createJsonEditor(toscaModel,editorData),
243                                         showSucAlert: true,
244                                         showMessage: "Successfully refreshed"
245                                 });
246                         })
247                         .catch(error => {
248                                 console.error("Error while refreshing the Operational Policy Json Representation");
249                                 this.setState({
250                                         showFailAlert: true,
251                                         showMessage: "Refreshing of UI failed"
252                                 });
253                         });
254                 }
255         }
256
257         disableAlert() {
258                 this.setState ({ showSucAlert: false, showFailAlert: false });
259         }
260
261         renderPdpGroupDropDown() {
262                 if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
263                         return (
264                                 <Form.Group as={Row} controlId="formPlaintextEmail">
265                                         <Form.Label column sm="2">Pdp Group Info</Form.Label>
266                                         <Col sm="3">
267                                                 <Select value={{ label: this.state.chosenPdpGroup, value: this.state.chosenPdpGroup }} onChange={this.handlePdpGroupChange} options={this.state.pdpGroupList} />
268                                         </Col>
269                                         <Col sm="3">
270                                                 <Select value={{ label: this.state.chosenPdpSubgroup, value: this.state.chosenPdpSubgroup }} onChange={this.handlePdpSubgroupChange} options={this.state.pdpSubgroupList} />
271                                         </Col>
272                                 </Form.Group>
273                         );
274                 }
275         }
276
277     renderOpenLoopMessage() {
278         if(this.state.policyInstanceType === OnapConstant.operationalPolicyType && this.state.loopCache.isOpenLoopTemplate()) {
279                 return (
280                                 "Operational Policy cannot be configured as only Open Loop is supported for this Template!"
281                         );
282                 }
283     }
284
285         renderModalTitle() {
286                 return (
287                                 <Modal.Title>Edit the policy</Modal.Title>
288                 );
289         }
290
291         renderButton() {
292             var allElement = [(<Button variant="secondary" onClick={this.handleClose}>
293                                                                 Close
294                          </Button>)];
295                 if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
296              allElement.push((
297                 <Button variant="primary" disabled={this.readOnly} onClick={this.handleSave}>
298                                 Save Changes
299                 </Button>
300              ));
301              allElement.push((
302                 <Button variant="primary" disabled={this.readOnly} onClick={this.handleRefresh}>
303                                 Refresh
304                 </Button>
305              ));
306                 }
307                 return allElement;
308         }
309
310         render() {
311                 return (
312                         <ModalStyled size="xl" backdrop="static" keyboard={false} show={this.state.show} onHide={this.handleClose}>
313                                 <Modal.Header closeButton>
314                                         {this.renderModalTitle()}
315                                 </Modal.Header>
316                                 <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
317                                         {this.state.showMessage}
318                                 </Alert>
319                                 <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
320                                         {this.state.showMessage}
321                                 </Alert>
322                                 <Modal.Body>
323                                         {this.renderOpenLoopMessage()}
324                                         <div id="editor" />
325                                         {this.renderPdpGroupDropDown()}
326                                 </Modal.Body>
327                                 <Modal.Footer>
328                                         {this.renderButton()}
329                                 </Modal.Footer>
330                         </ModalStyled>
331                 );
332         }
333 }