blob: 6b1ebe17821eaa4ba4f7410ae3b4a95a701863fa [file] [log] [blame]
sebdetc11160e2020-02-25 15:13:31 -08001/*-
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
24import React from 'react'
25import Button from 'react-bootstrap/Button';
xuegao635445a2020-03-02 11:37:20 +010026import Form from 'react-bootstrap/Form';
27import Col from 'react-bootstrap/Col';
28import Row from 'react-bootstrap/Row';
29import Select from 'react-select';
sebdetc11160e2020-02-25 15:13:31 -080030import Modal from 'react-bootstrap/Modal';
31import styled from 'styled-components';
32import LoopService from '../../../api/LoopService';
xuegaoe18ed702020-03-17 10:46:39 +010033import LoopCache from '../../../api/LoopCache';
sebdetc11160e2020-02-25 15:13:31 -080034import JSONEditor from '@json-editor/json-editor';
xuegaoe18ed702020-03-17 10:46:39 +010035import Alert from 'react-bootstrap/Alert';
sebdetc0ec0fc2020-05-18 12:31:11 +020036import OnapConstant from '../../../utils/OnapConstants';
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040037import OnapUtils from '../../../utils/OnapUtils';
sebdetc11160e2020-02-25 15:13:31 -080038
39const ModalStyled = styled(Modal)`
40 background-color: transparent;
41`
42
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040043const DivWhiteSpaceStyled = styled.div`
44 white-space: pre;
45`
46
sebdetc11160e2020-02-25 15:13:31 -080047export default class PolicyModal extends React.Component {
48
49 state = {
50 show: true,
51 loopCache: this.props.loopCache,
52 jsonEditor: null,
53 policyName: this.props.match.params.policyName,
54 // This is to indicate whether it's an operational or config policy (in terms of loop instance)
xuegao635445a2020-03-02 11:37:20 +010055 policyInstanceType: this.props.match.params.policyInstanceType,
56 pdpGroup: null,
57 pdpGroupList: [],
58 pdpSubgroupList: [],
59 chosenPdpGroup: '',
xuegaoe18ed702020-03-17 10:46:39 +010060 chosenPdpSubgroup: '',
61 showSucAlert: false,
62 showFailAlert: false
sebdetc11160e2020-02-25 15:13:31 -080063 };
64
65 constructor(props, context) {
66 super(props, context);
67 this.handleClose = this.handleClose.bind(this);
68 this.handleSave = this.handleSave.bind(this);
69 this.renderJsonEditor = this.renderJsonEditor.bind(this);
xuegao635445a2020-03-02 11:37:20 +010070 this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
71 this.handlePdpSubgroupChange = this.handlePdpSubgroupChange.bind(this);
sebdet2dd4e992020-03-04 15:47:39 -080072 this.createJsonEditor = this.createJsonEditor.bind(this);
xuegaoe18ed702020-03-17 10:46:39 +010073 this.handleRefresh = this.handleRefresh.bind(this);
74 this.disableAlert = this.disableAlert.bind(this);
sebdetc0ec0fc2020-05-18 12:31:11 +020075 this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this);
76 this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this);
77 this.renderModalTitle = this.renderModalTitle.bind(this);
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040078 this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
sebdetc11160e2020-02-25 15:13:31 -080079 }
80
81 handleSave() {
sebdetc11160e2020-02-25 15:13:31 -080082 var editorData = this.state.jsonEditor.getValue();
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040083 var errors = this.state.jsonEditor.validate();
84 errors = errors.concat(this.customValidation(editorData, this.state.loopCache.getTemplateName()));
sebdetc11160e2020-02-25 15:13:31 -080085
86 if (errors.length !== 0) {
87 console.error("Errors detected during policy data validation ", errors);
sebdet6e7d0482020-04-16 16:14:45 +020088 this.setState({
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040089 showFailAlert: true,
90 showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
91 });
sebdet2dd4e992020-03-04 15:47:39 -080092 return;
sebdetc11160e2020-02-25 15:13:31 -080093 }
94 else {
95 console.info("NO validation errors found in policy data");
sebdetc0ec0fc2020-05-18 12:31:11 +020096 if (this.state.policyInstanceType === OnapConstant.microServiceType) {
Ted Humphrey9dfd03b2020-07-07 03:37:37 -040097 this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData);
98 this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
99 LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => {
100 this.setState({ show: false });
101 this.props.history.push('/');
102 this.props.loadLoopFunction(this.state.loopCache.getLoopName());
103 });
sebdetc0ec0fc2020-05-18 12:31:11 +0200104 } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
sebdet2dd4e992020-03-04 15:47:39 -0800105 this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData);
xuegao635445a2020-03-02 11:37:20 +0100106 this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup);
107 LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => {
108 this.setState({ show: false });
Ted Humphrey9dfd03b2020-07-07 03:37:37 -0400109 this.props.history.push('/');
xuegao635445a2020-03-02 11:37:20 +0100110 this.props.loadLoopFunction(this.state.loopCache.getLoopName());
111 });
sebdetc11160e2020-02-25 15:13:31 -0800112 }
113 }
114 }
115
Ted Humphrey9dfd03b2020-07-07 03:37:37 -0400116 customValidation(editorData, templateName) {
117 // method for sub-classes to override with customized validation
118 return [];
119 }
120
sebdetc11160e2020-02-25 15:13:31 -0800121 handleClose() {
122 this.setState({ show: false });
123 this.props.history.push('/');
124 }
125
126 componentDidMount() {
127 this.renderJsonEditor();
128 }
129
Ted Humphrey9dfd03b2020-07-07 03:37:37 -0400130 componentDidUpdate() {
131 if (this.state.showSucAlert === true || this.state.showFailAlert === true) {
132 let modalElement = document.getElementById("policyModal")
133 if (modalElement) {
134 modalElement.scrollTo(0, 0);
135 }
136 }
137 }
138
sebdet2dd4e992020-03-04 15:47:39 -0800139 createJsonEditor(toscaModel, editorData) {
sebdet82775722020-03-16 07:07:18 -0700140 JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
141 getTab: function(text,tabId) {
142 var liel = document.createElement('li');
143 liel.classList.add('nav-item');
144 var ael = document.createElement("a");
145 ael.classList.add("nav-link");
146 ael.setAttribute("style",'padding:10px;max-width:160px;');
147 ael.setAttribute("href", "#" + tabId);
148 ael.setAttribute('data-toggle', 'tab');
149 text.setAttribute("style",'word-wrap:break-word;');
150 ael.appendChild(text);
151 liel.appendChild(ael);
152 return liel;
153 }
154 });
sebdet2dd4e992020-03-04 15:47:39 -0800155 return new JSONEditor(document.getElementById("editor"),
156 { schema: toscaModel,
157 startval: editorData,
sebdet82775722020-03-16 07:07:18 -0700158 theme: 'myBootstrap4',
sebdet2dd4e992020-03-04 15:47:39 -0800159 object_layout: 'grid',
sebdet1b4f20d2020-03-17 07:47:03 -0700160 disable_properties: false,
sebdet2dd4e992020-03-04 15:47:39 -0800161 disable_edit_json: false,
162 disable_array_reorder: true,
163 disable_array_delete_last_row: true,
164 disable_array_delete_all_rows: false,
sebdet49ab84a2020-03-13 15:27:41 -0700165 array_controls_top: true,
166 keep_oneof_values: false,
167 collapsed:true,
sebdet2dd4e992020-03-04 15:47:39 -0800168 show_errors: 'always',
169 display_required_only: false,
sebdet82775722020-03-16 07:07:18 -0700170 show_opt_in: false,
sebdet2dd4e992020-03-04 15:47:39 -0800171 prompt_before_delete: true,
sebdet82775722020-03-16 07:07:18 -0700172 required_by_default: false
sebdet2dd4e992020-03-04 15:47:39 -0800173 })
174 }
175
sebdetc11160e2020-02-25 15:13:31 -0800176 renderJsonEditor() {
177 console.debug("Rendering PolicyModal ", this.state.policyName);
178 var toscaModel = {};
xuegao635445a2020-03-02 11:37:20 +0100179 var editorData = {};
180 var pdpGroupValues = {};
181 var chosenPdpGroupValue, chosenPdpSubgroupValue;
sebdetc0ec0fc2020-05-18 12:31:11 +0200182 if (this.state.policyInstanceType === OnapConstant.microServiceType) {
xuegao635445a2020-03-02 11:37:20 +0100183 toscaModel = this.state.loopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
184 editorData = this.state.loopCache.getMicroServicePropertiesForName(this.state.policyName);
sebdet2dd4e992020-03-04 15:47:39 -0800185 pdpGroupValues = this.state.loopCache.getMicroServiceSupportedPdpGroup(this.state.policyName);
xuegao635445a2020-03-02 11:37:20 +0100186 chosenPdpGroupValue = this.state.loopCache.getMicroServicePdpGroup(this.state.policyName);
187 chosenPdpSubgroupValue = this.state.loopCache.getMicroServicePdpSubgroup(this.state.policyName);
sebdetc0ec0fc2020-05-18 12:31:11 +0200188 } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
xuegao635445a2020-03-02 11:37:20 +0100189 toscaModel = this.state.loopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
190 editorData = this.state.loopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
sebdet2dd4e992020-03-04 15:47:39 -0800191 pdpGroupValues = this.state.loopCache.getOperationalPolicySupportedPdpGroup(this.state.policyName);
xuegao635445a2020-03-02 11:37:20 +0100192 chosenPdpGroupValue = this.state.loopCache.getOperationalPolicyPdpGroup(this.state.policyName);
193 chosenPdpSubgroupValue = this.state.loopCache.getOperationalPolicyPdpSubgroup(this.state.policyName);
194 }
sebdetc11160e2020-02-25 15:13:31 -0800195
196 if (toscaModel == null) {
197 return;
198 }
199
sebdet2dd4e992020-03-04 15:47:39 -0800200 var pdpSubgroupValues = [];
201 if (typeof(chosenPdpGroupValue) !== "undefined") {
xuegao635445a2020-03-02 11:37:20 +0100202 var selectedPdpGroup = pdpGroupValues.filter(entry => (Object.keys(entry)[0] === chosenPdpGroupValue));
sebdet2dd4e992020-03-04 15:47:39 -0800203 pdpSubgroupValues = selectedPdpGroup[0][chosenPdpGroupValue].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
xuegao635445a2020-03-02 11:37:20 +0100204 }
sebdet2dd4e992020-03-04 15:47:39 -0800205 this.setState({
206 jsonEditor: this.createJsonEditor(toscaModel,editorData),
207 pdpGroup: pdpGroupValues,
208 pdpGroupList: pdpGroupValues.map(entry => {
209 return { label: Object.keys(entry)[0], value: Object.keys(entry)[0] };
210 }),
211 pdpSubgroupList: pdpSubgroupValues,
212 chosenPdpGroup: chosenPdpGroupValue,
213 chosenPdpSubgroup: chosenPdpSubgroupValue
214 })
xuegao635445a2020-03-02 11:37:20 +0100215 }
216
217 handlePdpGroupChange(e) {
218 var selectedPdpGroup = this.state.pdpGroup.filter(entry => (Object.keys(entry)[0] === e.value));
219 const pdpSubgroupValues = selectedPdpGroup[0][e.value].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } });
220 if (this.state.chosenPdpGroup !== e.value) {
sebdet2dd4e992020-03-04 15:47:39 -0800221 this.setState({
xuegao635445a2020-03-02 11:37:20 +0100222 chosenPdpGroup: e.value,
223 chosenPdpSubgroup: '',
224 pdpSubgroupList: pdpSubgroupValues
225 });
226 }
227 }
228
229 handlePdpSubgroupChange(e) {
230 this.setState({ chosenPdpSubgroup: e.value });
sebdetc11160e2020-02-25 15:13:31 -0800231 }
232
xuegaoe18ed702020-03-17 10:46:39 +0100233 handleRefresh() {
234 var newLoopCache, toscaModel, editorData;
sebdetc0ec0fc2020-05-18 12:31:11 +0200235 if (this.state.policyInstanceType === OnapConstant.microServiceType) {
xuegaoe18ed702020-03-17 10:46:39 +0100236 LoopService.refreshMicroServicePolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
237 newLoopCache = new LoopCache(data);
238 toscaModel = newLoopCache.getMicroServiceJsonRepresentationForName(this.state.policyName);
239 editorData = newLoopCache.getMicroServicePropertiesForName(this.state.policyName);
240 document.getElementById("editor").innerHTML = "";
241 this.setState({
242 loopCache: newLoopCache,
243 jsonEditor: this.createJsonEditor(toscaModel,editorData),
244 showSucAlert: true,
245 showMessage: "Successfully refreshed"
246 });
247 })
248 .catch(error => {
249 console.error("Error while refreshing the Operational Policy Json Representation");
250 this.setState({
251 showFailAlert: true,
252 showMessage: "Refreshing of UI failed"
253 });
254 });
sebdetc0ec0fc2020-05-18 12:31:11 +0200255 } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) {
xuegaoe18ed702020-03-17 10:46:39 +0100256 LoopService.refreshOperationalPolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => {
257 var newLoopCache = new LoopCache(data);
258 toscaModel = newLoopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName);
259 editorData = newLoopCache.getOperationalPolicyPropertiesForName(this.state.policyName);
260 document.getElementById("editor").innerHTML = "";
261 this.setState({
262 loopCache: newLoopCache,
263 jsonEditor: this.createJsonEditor(toscaModel,editorData),
264 showSucAlert: true,
265 showMessage: "Successfully refreshed"
266 });
267 })
268 .catch(error => {
269 console.error("Error while refreshing the Operational Policy Json Representation");
270 this.setState({
271 showFailAlert: true,
272 showMessage: "Refreshing of UI failed"
273 });
274 });
275 }
276 }
277
278 disableAlert() {
279 this.setState ({ showSucAlert: false, showFailAlert: false });
280 }
281
sebdetc0ec0fc2020-05-18 12:31:11 +0200282 renderPdpGroupDropDown() {
283 if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
284 return (
285 <Form.Group as={Row} controlId="formPlaintextEmail">
286 <Form.Label column sm="2">Pdp Group Info</Form.Label>
287 <Col sm="3">
288 <Select value={{ label: this.state.chosenPdpGroup, value: this.state.chosenPdpGroup }} onChange={this.handlePdpGroupChange} options={this.state.pdpGroupList} />
289 </Col>
290 <Col sm="3">
291 <Select value={{ label: this.state.chosenPdpSubgroup, value: this.state.chosenPdpSubgroup }} onChange={this.handlePdpSubgroupChange} options={this.state.pdpSubgroupList} />
292 </Col>
293 </Form.Group>
294 );
295 }
296 }
297
298 renderOpenLoopMessage() {
299 if(this.state.policyInstanceType === OnapConstant.operationalPolicyType && this.state.loopCache.isOpenLoopTemplate()) {
300 return (
301 "Operational Policy cannot be configured as only Open Loop is supported for this Template!"
302 );
303 }
304 }
305
306 renderModalTitle() {
307 return (
308 <Modal.Title>Edit the policy</Modal.Title>
309 );
310 }
311
312 renderButton() {
313 var allElement = [(<Button variant="secondary" onClick={this.handleClose}>
314 Close
315 </Button>)];
316 if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) {
317 allElement.push((
318 <Button variant="primary" disabled={this.readOnly} onClick={this.handleSave}>
319 Save Changes
320 </Button>
321 ));
322 allElement.push((
323 <Button variant="primary" disabled={this.readOnly} onClick={this.handleRefresh}>
324 Refresh
325 </Button>
326 ));
327 }
328 return allElement;
329 }
330
sebdetc11160e2020-02-25 15:13:31 -0800331 render() {
332 return (
sebdetc0ec0fc2020-05-18 12:31:11 +0200333 <ModalStyled size="xl" backdrop="static" keyboard={false} show={this.state.show} onHide={this.handleClose}>
sebdetc11160e2020-02-25 15:13:31 -0800334 <Modal.Header closeButton>
sebdetc0ec0fc2020-05-18 12:31:11 +0200335 {this.renderModalTitle()}
sebdetc11160e2020-02-25 15:13:31 -0800336 </Modal.Header>
Ted Humphrey9dfd03b2020-07-07 03:37:37 -0400337 <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible>
338 <DivWhiteSpaceStyled>
339 {this.state.showMessage}
340 </DivWhiteSpaceStyled>
341 </Alert>
342 <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
343 <DivWhiteSpaceStyled>
344 {this.state.showMessage}
345 </DivWhiteSpaceStyled>
346 </Alert>
sebdetc11160e2020-02-25 15:13:31 -0800347 <Modal.Body>
sebdetc0ec0fc2020-05-18 12:31:11 +0200348 {this.renderOpenLoopMessage()}
sebdetc11160e2020-02-25 15:13:31 -0800349 <div id="editor" />
sebdetc0ec0fc2020-05-18 12:31:11 +0200350 {this.renderPdpGroupDropDown()}
sebdetc11160e2020-02-25 15:13:31 -0800351 </Modal.Body>
352 <Modal.Footer>
sebdetc0ec0fc2020-05-18 12:31:11 +0200353 {this.renderButton()}
sebdetc11160e2020-02-25 15:13:31 -0800354 </Modal.Footer>
355 </ModalStyled>
sebdetc11160e2020-02-25 15:13:31 -0800356 );
357 }
Ted Humphrey9dfd03b2020-07-07 03:37:37 -0400358}