blob: dfebc51d8eba498a5775f600f26d98ce42d39671 [file] [log] [blame]
sebdeteb8e3f12021-01-24 18:12:36 +01001/*-
2 * ============LICENSE_START=======================================================
3 * ONAP POLICY-CLAMP
4 * ================================================================================
5 * Copyright (C) 2021 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, { forwardRef } from 'react'
25import Button from 'react-bootstrap/Button';
26import Modal from 'react-bootstrap/Modal';
27import styled from 'styled-components';
sebdet37285472021-02-15 18:09:38 +010028import AddBox from '@material-ui/icons/AddBox';
29import ArrowDownward from '@material-ui/icons/ArrowDownward';
30import Check from '@material-ui/icons/Check';
sebdeteb8e3f12021-01-24 18:12:36 +010031import ChevronLeft from '@material-ui/icons/ChevronLeft';
32import ChevronRight from '@material-ui/icons/ChevronRight';
33import Clear from '@material-ui/icons/Clear';
sebdet37285472021-02-15 18:09:38 +010034import DeleteOutline from '@material-ui/icons/DeleteOutline';
35import Edit from '@material-ui/icons/Edit';
36import FilterList from '@material-ui/icons/FilterList';
sebdeteb8e3f12021-01-24 18:12:36 +010037import FirstPage from '@material-ui/icons/FirstPage';
38import LastPage from '@material-ui/icons/LastPage';
sebdet37285472021-02-15 18:09:38 +010039import Remove from '@material-ui/icons/Remove';
40import SaveAlt from '@material-ui/icons/SaveAlt';
sebdeteb8e3f12021-01-24 18:12:36 +010041import Search from '@material-ui/icons/Search';
sebdet37285472021-02-15 18:09:38 +010042import ViewColumn from '@material-ui/icons/ViewColumn';
43import FormControlLabel from '@material-ui/core/FormControlLabel';
44import Switch from '@material-ui/core/Switch';
sebdeteb8e3f12021-01-24 18:12:36 +010045import MaterialTable from "material-table";
sebdeteb8e3f12021-01-24 18:12:36 +010046import PolicyService from '../../../api/PolicyService';
sebdet3718a162021-02-12 17:18:47 +010047import PolicyToscaService from '../../../api/PolicyToscaService';
sebdeteb8e3f12021-01-24 18:12:36 +010048import Select from 'react-select';
sebdet3718a162021-02-12 17:18:47 +010049import JSONEditor from '@json-editor/json-editor';
sebdetc427e642021-02-17 17:53:17 +010050import OnapUtils from '../../../utils/OnapUtils';
51import Alert from 'react-bootstrap/Alert';
52
53const DivWhiteSpaceStyled = styled.div`
54 white-space: pre;
55`
sebdeteb8e3f12021-01-24 18:12:36 +010056
57const ModalStyled = styled(Modal)`
sebdet3718a162021-02-12 17:18:47 +010058 @media (min-width: 1200px) {
59 .modal-xl {
60 max-width: 96%;
61 }
62 }
sebdeteb8e3f12021-01-24 18:12:36 +010063 background-color: transparent;
64`
sebdet37285472021-02-15 18:09:38 +010065const JsonEditorDiv = styled.div`
66 margin-top: 20px;
67 background-color: ${props => props.theme.toscaTextareaBackgroundColor};
68 text-align: justify;
69 font-size: ${props => props.theme.toscaTextareaFontSize};
70 width: 100%;
71 height: 30%;
72 border: 1px solid black;
73`
74
sebdeteb8e3f12021-01-24 18:12:36 +010075
76const standardCellStyle = { border: '1px solid black' };
77const cellPdpGroupStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black'};
78const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
79const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
sebdeteb8e3f12021-01-24 18:12:36 +010080
81export default class ViewAllPolicies extends React.Component {
82 state = {
83 show: true,
84 content: 'Please select a policy to display it',
sebdetc427e642021-02-17 17:53:17 +010085 selectedRowId: -1,
sebdeteb8e3f12021-01-24 18:12:36 +010086 policiesListData: [],
sebdet37285472021-02-15 18:09:38 +010087 prefixGrouping: false,
sebdetc427e642021-02-17 17:53:17 +010088 showSuccessAlert: false,
89 showFailAlert: false,
sebdeteb8e3f12021-01-24 18:12:36 +010090 policyColumnsDefinition: [
91 {
sebdeteb8e3f12021-01-24 18:12:36 +010092 title: "Policy Name", field: "name",
93 cellStyle: standardCellStyle,
94 headerStyle: headerStyle
95 },
96 {
97 title: "Policy Version", field: "version",
98 cellStyle: standardCellStyle,
99 headerStyle: headerStyle
100 },
101 {
102 title: "Policy Type", field: "type",
103 cellStyle: standardCellStyle,
104 headerStyle: headerStyle
105 },
106 {
107 title: "Policy Type Version", field: "type_version",
108 cellStyle: standardCellStyle,
109 headerStyle: headerStyle
110 },
111 {
112 title: "Deployed in PDP", field: "pdpGroupInfo.pdpGroup",
113 cellStyle: cellPdpGroupStyle,
114 headerStyle: headerStyle,
sebdet37285472021-02-15 18:09:38 +0100115 render: rowData => this.renderPdpGroupDropBox(rowData),
116 grouping: false
sebdeteb8e3f12021-01-24 18:12:36 +0100117 },
118 {
119 title: "PDP Group", field: "pdpGroupInfo.pdpGroup",
120 cellStyle: cellPdpGroupStyle,
121 headerStyle: headerStyle
122 },
123 {
124 title: "PDP SubGroup", field: "pdpGroupInfo.pdpSubGroup",
125 cellStyle: cellPdpGroupStyle,
126 headerStyle: headerStyle
127 }
128 ],
129 tableIcons: {
sebdet37285472021-02-15 18:09:38 +0100130 Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
131 Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
132 Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
133 Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
134 DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
135 Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
136 Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
137 Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
sebdeteb8e3f12021-01-24 18:12:36 +0100138 FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
139 LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
140 NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
141 PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
142 ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
143 Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
sebdet37285472021-02-15 18:09:38 +0100144 SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />),
145 ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
146 ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
sebdeteb8e3f12021-01-24 18:12:36 +0100147 }
148 };
149
150 constructor(props, context) {
151 super(props, context);
152 this.handleClose = this.handleClose.bind(this);
153 this.renderPdpGroupDropBox = this.renderPdpGroupDropBox.bind(this);
154 this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
sebdet3718a162021-02-12 17:18:47 +0100155 this.createJsonEditor = this.createJsonEditor.bind(this);
sebdet37285472021-02-15 18:09:38 +0100156 this.handlePrefixGrouping = this.handlePrefixGrouping.bind(this);
sebdeta0a3a032021-02-16 14:53:43 +0100157 this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
sebdet37285472021-02-15 18:09:38 +0100158 this.handleUpdatePolicy = this.handleUpdatePolicy.bind(this);
sebdetc427e642021-02-17 17:53:17 +0100159 this.handleCreateNewVersion = this.handleCreateNewVersion.bind(this);
160 this.disableAlert = this.disableAlert.bind(this);
sebdeteb8e3f12021-01-24 18:12:36 +0100161 this.getAllPolicies();
162
163 }
164
165 handlePdpGroupChange(e) {
166 let pdpSplit = e.value.split("/");
167 let selectedPdpGroup = pdpSplit[0];
168 let selectedSubPdpGroup = pdpSplit[1];
169 if (typeof selectedSubPdpGroup !== "undefined") {
sebdet3718a162021-02-12 17:18:47 +0100170 let temp = this.state.policiesListData;
sebdetc427e642021-02-17 17:53:17 +0100171 temp[this.state.selectedRowId]["pdpGroupInfo"] = {"pdpGroup":selectedPdpGroup,"pdpSubGroup":selectedSubPdpGroup};
sebdet3718a162021-02-12 17:18:47 +0100172 this.setState({policiesListData: temp});
sebdeteb8e3f12021-01-24 18:12:36 +0100173 } else {
sebdetc427e642021-02-17 17:53:17 +0100174 delete this.state.policiesListData[this.state.selectedRowId]["pdpGroupInfo"];
sebdeteb8e3f12021-01-24 18:12:36 +0100175 }
176 }
177
sebdet3718a162021-02-12 17:18:47 +0100178 createJsonEditor(toscaModel, editorData) {
sebdet37285472021-02-15 18:09:38 +0100179 document.getElementById("policy-editor").innerHTML = "";
sebdet3718a162021-02-12 17:18:47 +0100180 JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
181 getTab: function(text,tabId) {
182 var liel = document.createElement('li');
183 liel.classList.add('nav-item');
184 var ael = document.createElement("a");
185 ael.classList.add("nav-link");
186 ael.setAttribute("style",'padding:10px;max-width:160px;');
187 ael.setAttribute("href", "#" + tabId);
188 ael.setAttribute('data-toggle', 'tab');
189 text.setAttribute("style",'word-wrap:break-word;');
190 ael.appendChild(text);
191 liel.appendChild(ael);
192 return liel;
193 }
194 });
195 return new JSONEditor(document.getElementById("policy-editor"),
sebdet37285472021-02-15 18:09:38 +0100196 {
197 schema: toscaModel,
sebdet3718a162021-02-12 17:18:47 +0100198 startval: editorData,
199 theme: 'myBootstrap4',
200 object_layout: 'grid',
201 disable_properties: false,
202 disable_edit_json: false,
203 disable_array_reorder: true,
204 disable_array_delete_last_row: true,
205 disable_array_delete_all_rows: false,
206 array_controls_top: true,
207 keep_oneof_values: false,
208 collapsed:true,
209 show_errors: 'always',
210 display_required_only: false,
211 show_opt_in: false,
212 prompt_before_delete: true,
213 required_by_default: false
214 })
215 }
216
sebdeteb8e3f12021-01-24 18:12:36 +0100217 renderPdpGroupDropBox(dataRow) {
218 let optionItems = [{label: "NOT DEPLOYED", value: "NOT DEPLOYED"}];
219 let selectedItem = {label: "NOT DEPLOYED", value: "NOT DEPLOYED"};
220 if (typeof dataRow.supportedPdpGroups !== "undefined") {
221 for (const pdpGroup of dataRow["supportedPdpGroups"]) {
222 for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
223 optionItems.push({ label: Object.keys(pdpGroup)[0]+"/"+pdpSubGroup,
224 value: Object.keys(pdpGroup)[0]+"/"+pdpSubGroup });
225 }
226 }
227 }
228 if (typeof dataRow.pdpGroupInfo !== "undefined") {
229 selectedItem = {label: dataRow["pdpGroupInfo"]["pdpGroup"]+"/"+dataRow["pdpGroupInfo"]["pdpSubGroup"],
230 value: dataRow["pdpGroupInfo"]["pdpGroup"]+"/"+dataRow["pdpGroupInfo"]["pdpSubGroup"]};
231 }
232 return (<div style={{width: '250px'}}><Select value={selectedItem} options={optionItems} onChange={this.handlePdpGroupChange}/></div>);
233 }
234
235 getAllPolicies() {
236 PolicyService.getPoliciesList().then(allPolicies => {
237 this.setState({ policiesListData: allPolicies["policies"] })
238 });
239 }
240
241 handleClose() {
242 this.setState({ show: false });
243 this.props.history.push('/')
244 }
245
sebdet3718a162021-02-12 17:18:47 +0100246 handleOnRowClick(rowData) {
247 PolicyToscaService.getToscaPolicyModel(rowData["type"], rowData["type_version"]).then(respJsonPolicyTosca => {
248 this.setState({
sebdetc427e642021-02-17 17:53:17 +0100249 selectedRowId: rowData.tableData.id,
250 selectedRowIdJsonSchema: respJsonPolicyTosca,
251 selectedRowIdPolicyProperties: rowData["properties"],
sebdet3718a162021-02-12 17:18:47 +0100252 jsonEditorForPolicy: this.createJsonEditor(respJsonPolicyTosca, rowData["properties"])
253 });
254 });
255 }
256
sebdet37285472021-02-15 18:09:38 +0100257 handlePrefixGrouping(event) {
258 this.setState({prefixGrouping: event.target.checked});
sebdeta0a3a032021-02-16 14:53:43 +0100259 }
sebdet37285472021-02-15 18:09:38 +0100260
sebdeta0a3a032021-02-16 14:53:43 +0100261 handleDeletePolicy(event, rowData) {
sebdet37285472021-02-15 18:09:38 +0100262 return null;
263 }
264
sebdetc427e642021-02-17 17:53:17 +0100265 customValidation(editorData) {
266 // method for sub-classes to override with customized validation
267 return [];
268 }
269
270 handleCreateNewVersion() {
271 var editorData = this.state.jsonEditorForPolicy.getValue();
272 var errors = this.state.jsonEditorForPolicy.validate();
273 errors = errors.concat(this.customValidation(editorData));
274
275 if (errors.length !== 0) {
276 console.error("Errors detected during policy data validation ", errors);
277 this.setState({
278 showFailAlert: true,
279 showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
280 });
281 return;
282 } else {
283 console.info("NO validation errors found in policy data");
284 let newPolicy = JSON.parse(JSON.stringify(this.state.policiesListData[this.state.selectedRowId]));
285 newPolicy["properties"] = editorData;
286 let newVersion = this.bumpVersion(newPolicy["version"]);
287 newPolicy["version"] = newVersion;
288 newPolicy["metadata"]["policy-version"] = newVersion;
289 // Remove stuff added by UI
290 delete newPolicy["tableData"];
291 PolicyService.createNewPolicy(newPolicy["type"], newPolicy["type_version"], newPolicy).then(respPolicyCreation => {
292 if (respPolicyCreation === "") {
293 //it indicates a failure
294 this.setState({
295 showFailAlert: true,
296 showMessage: 'Policy Creation Failure'
297 });
298 } else {
299 this.setState({
300 showSuccessAlert: true,
301 showMessage: 'Policy in version ' + newVersion + ' created successfully'
302 });
303 }
304 })
305 }
306 }
307
308 bumpVersion(versionToBump) {
309 let semVer = versionToBump.split(".");
310 return parseInt(semVer[0])+1 + "." + semVer[1] + "." + semVer[2];
sebdeta0a3a032021-02-16 14:53:43 +0100311 }
312
313 handleUpdatePolicy() {
314 this.setState({ show: false });
315 this.props.history.push('/')
316 }
317
sebdetc427e642021-02-17 17:53:17 +0100318 disableAlert() {
319 this.setState ({ showSuccessAlert: false, showFailAlert: false });
320 }
321
sebdeteb8e3f12021-01-24 18:12:36 +0100322 render() {
323 return (
sebdet37285472021-02-15 18:09:38 +0100324 <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}>
sebdeteb8e3f12021-01-24 18:12:36 +0100325 <Modal.Header closeButton>
326 </Modal.Header>
sebdetc427e642021-02-17 17:53:17 +0100327
sebdeteb8e3f12021-01-24 18:12:36 +0100328 <Modal.Body>
sebdet37285472021-02-15 18:09:38 +0100329 <FormControlLabel
330 control={<Switch checked={this.state.prefixGrouping} onChange={this.handlePrefixGrouping} />}
331 label="Group by prefix"
332 />
sebdeteb8e3f12021-01-24 18:12:36 +0100333 <MaterialTable
334 title={"View All Policies in Policy Engine"}
335 data={this.state.policiesListData}
336 columns={this.state.policyColumnsDefinition}
337 icons={this.state.tableIcons}
sebdet3718a162021-02-12 17:18:47 +0100338 onRowClick={(event, rowData) => {this.handleOnRowClick(rowData)}}
sebdeteb8e3f12021-01-24 18:12:36 +0100339 options={{
sebdet37285472021-02-15 18:09:38 +0100340 grouping: true,
341 exportButton: true,
sebdeteb8e3f12021-01-24 18:12:36 +0100342 headerStyle:rowHeaderStyle,
343 rowStyle: rowData => ({
sebdetc427e642021-02-17 17:53:17 +0100344 backgroundColor: (this.state.selectedRowId !== -1 && this.state.selectedRowId === rowData.tableData.id) ? '#EEE' : '#FFF'
sebdeteb8e3f12021-01-24 18:12:36 +0100345 })
346 }}
sebdet37285472021-02-15 18:09:38 +0100347 actions={[
348 {
349 icon: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
350 tooltip: 'Delete Policy',
sebdeta0a3a032021-02-16 14:53:43 +0100351 onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
sebdet37285472021-02-15 18:09:38 +0100352 }
353 ]}
sebdeteb8e3f12021-01-24 18:12:36 +0100354 />
sebdet37285472021-02-15 18:09:38 +0100355 <JsonEditorDiv>
356 <h5>Policy Properties Editor</h5>
357 <div id="policy-editor" title="Policy Properties"/>
sebdetc427e642021-02-17 17:53:17 +0100358 <Button variant="secondary" title="Create a new policy version from the defined parameters"
359 onClick={this.handleCreateNewVersion}>Create New Version</Button>
360 <Button variant="secondary" title="Update the current policy version, BE CAREFUL this will undeploy the policy from PDP, delete it and then recreate the policy"
361 onClick={this.handleUpdatePolicy}>Update Current Version</Button>
sebdet37285472021-02-15 18:09:38 +0100362 </JsonEditorDiv>
sebdetc427e642021-02-17 17:53:17 +0100363 <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible>
364 <DivWhiteSpaceStyled>
365 {this.state.showMessage}
366 </DivWhiteSpaceStyled>
367 </Alert>
368 <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
369 <DivWhiteSpaceStyled>
370 {this.state.showMessage}
371 </DivWhiteSpaceStyled>
372 </Alert>
sebdeteb8e3f12021-01-24 18:12:36 +0100373 </Modal.Body>
374 <Modal.Footer>
375 <Button variant="secondary" onClick={this.handleClose}>Close</Button>
376 </Modal.Footer>
377 </ModalStyled>
378 );
379 }
380 }