blob: b159584dd14a1f36d608db22ac2371868e754322 [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';
sebdetea2969f2021-02-25 13:58:36 +010052import Tabs from 'react-bootstrap/Tabs';
53import Tab from 'react-bootstrap/Tab';
sebdetc427e642021-02-17 17:53:17 +010054
55const DivWhiteSpaceStyled = styled.div`
sebdetea2969f2021-02-25 13:58:36 +010056 white-space: pre;
sebdetc427e642021-02-17 17:53:17 +010057`
sebdeteb8e3f12021-01-24 18:12:36 +010058
59const ModalStyled = styled(Modal)`
sebdet3718a162021-02-12 17:18:47 +010060 @media (min-width: 1200px) {
61 .modal-xl {
62 max-width: 96%;
63 }
64 }
sebdeteb8e3f12021-01-24 18:12:36 +010065 background-color: transparent;
66`
sebdet37285472021-02-15 18:09:38 +010067const JsonEditorDiv = styled.div`
68 margin-top: 20px;
69 background-color: ${props => props.theme.toscaTextareaBackgroundColor};
70 text-align: justify;
71 font-size: ${props => props.theme.toscaTextareaFontSize};
72 width: 100%;
73 height: 30%;
74 border: 1px solid black;
75`
76
sebdeteb8e3f12021-01-24 18:12:36 +010077
78const standardCellStyle = { border: '1px solid black' };
79const cellPdpGroupStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black'};
80const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
81const rowHeaderStyle = {backgroundColor:'#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black'};
sebdeteb8e3f12021-01-24 18:12:36 +010082
83export default class ViewAllPolicies extends React.Component {
84 state = {
85 show: true,
86 content: 'Please select a policy to display it',
sebdetc427e642021-02-17 17:53:17 +010087 selectedRowId: -1,
sebdeteb8e3f12021-01-24 18:12:36 +010088 policiesListData: [],
sebdet37285472021-02-15 18:09:38 +010089 prefixGrouping: false,
sebdetc427e642021-02-17 17:53:17 +010090 showSuccessAlert: false,
91 showFailAlert: false,
sebdeteb8e3f12021-01-24 18:12:36 +010092 policyColumnsDefinition: [
93 {
sebdeteb8e3f12021-01-24 18:12:36 +010094 title: "Policy Name", field: "name",
95 cellStyle: standardCellStyle,
96 headerStyle: headerStyle
97 },
98 {
99 title: "Policy Version", field: "version",
100 cellStyle: standardCellStyle,
101 headerStyle: headerStyle
102 },
103 {
104 title: "Policy Type", field: "type",
105 cellStyle: standardCellStyle,
106 headerStyle: headerStyle
107 },
108 {
109 title: "Policy Type Version", field: "type_version",
110 cellStyle: standardCellStyle,
111 headerStyle: headerStyle
112 },
113 {
114 title: "Deployed in PDP", field: "pdpGroupInfo.pdpGroup",
115 cellStyle: cellPdpGroupStyle,
116 headerStyle: headerStyle,
sebdet37285472021-02-15 18:09:38 +0100117 render: rowData => this.renderPdpGroupDropBox(rowData),
118 grouping: false
sebdeteb8e3f12021-01-24 18:12:36 +0100119 },
120 {
121 title: "PDP Group", field: "pdpGroupInfo.pdpGroup",
122 cellStyle: cellPdpGroupStyle,
123 headerStyle: headerStyle
124 },
125 {
126 title: "PDP SubGroup", field: "pdpGroupInfo.pdpSubGroup",
127 cellStyle: cellPdpGroupStyle,
128 headerStyle: headerStyle
129 }
130 ],
131 tableIcons: {
sebdet37285472021-02-15 18:09:38 +0100132 Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
133 Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
134 Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
135 Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
136 DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
137 Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
138 Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />),
139 Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
sebdeteb8e3f12021-01-24 18:12:36 +0100140 FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
141 LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />),
142 NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
143 PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />),
144 ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
145 Search: forwardRef((props, ref) => <Search {...props} ref={ref} />),
sebdet37285472021-02-15 18:09:38 +0100146 SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />),
147 ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />),
148 ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />)
sebdeteb8e3f12021-01-24 18:12:36 +0100149 }
150 };
151
152 constructor(props, context) {
153 super(props, context);
154 this.handleClose = this.handleClose.bind(this);
155 this.renderPdpGroupDropBox = this.renderPdpGroupDropBox.bind(this);
156 this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
sebdet3718a162021-02-12 17:18:47 +0100157 this.createJsonEditor = this.createJsonEditor.bind(this);
sebdet37285472021-02-15 18:09:38 +0100158 this.handlePrefixGrouping = this.handlePrefixGrouping.bind(this);
sebdeta0a3a032021-02-16 14:53:43 +0100159 this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
sebdet37285472021-02-15 18:09:38 +0100160 this.handleUpdatePolicy = this.handleUpdatePolicy.bind(this);
sebdetc427e642021-02-17 17:53:17 +0100161 this.handleCreateNewVersion = this.handleCreateNewVersion.bind(this);
162 this.disableAlert = this.disableAlert.bind(this);
sebdeteb8e3f12021-01-24 18:12:36 +0100163 this.getAllPolicies();
164
165 }
166
167 handlePdpGroupChange(e) {
168 let pdpSplit = e.value.split("/");
169 let selectedPdpGroup = pdpSplit[0];
170 let selectedSubPdpGroup = pdpSplit[1];
171 if (typeof selectedSubPdpGroup !== "undefined") {
sebdet3718a162021-02-12 17:18:47 +0100172 let temp = this.state.policiesListData;
sebdetc427e642021-02-17 17:53:17 +0100173 temp[this.state.selectedRowId]["pdpGroupInfo"] = {"pdpGroup":selectedPdpGroup,"pdpSubGroup":selectedSubPdpGroup};
sebdet3718a162021-02-12 17:18:47 +0100174 this.setState({policiesListData: temp});
sebdeteb8e3f12021-01-24 18:12:36 +0100175 } else {
sebdetc427e642021-02-17 17:53:17 +0100176 delete this.state.policiesListData[this.state.selectedRowId]["pdpGroupInfo"];
sebdeteb8e3f12021-01-24 18:12:36 +0100177 }
178 }
179
sebdet3718a162021-02-12 17:18:47 +0100180 createJsonEditor(toscaModel, editorData) {
sebdet37285472021-02-15 18:09:38 +0100181 document.getElementById("policy-editor").innerHTML = "";
sebdet3718a162021-02-12 17:18:47 +0100182 JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
183 getTab: function(text,tabId) {
184 var liel = document.createElement('li');
185 liel.classList.add('nav-item');
186 var ael = document.createElement("a");
187 ael.classList.add("nav-link");
188 ael.setAttribute("style",'padding:10px;max-width:160px;');
189 ael.setAttribute("href", "#" + tabId);
190 ael.setAttribute('data-toggle', 'tab');
191 text.setAttribute("style",'word-wrap:break-word;');
192 ael.appendChild(text);
193 liel.appendChild(ael);
194 return liel;
195 }
196 });
197 return new JSONEditor(document.getElementById("policy-editor"),
sebdet37285472021-02-15 18:09:38 +0100198 {
199 schema: toscaModel,
sebdet3718a162021-02-12 17:18:47 +0100200 startval: editorData,
201 theme: 'myBootstrap4',
202 object_layout: 'grid',
203 disable_properties: false,
204 disable_edit_json: false,
205 disable_array_reorder: true,
206 disable_array_delete_last_row: true,
207 disable_array_delete_all_rows: false,
208 array_controls_top: true,
209 keep_oneof_values: false,
210 collapsed:true,
211 show_errors: 'always',
212 display_required_only: false,
213 show_opt_in: false,
214 prompt_before_delete: true,
215 required_by_default: false
216 })
217 }
218
sebdeteb8e3f12021-01-24 18:12:36 +0100219 renderPdpGroupDropBox(dataRow) {
220 let optionItems = [{label: "NOT DEPLOYED", value: "NOT DEPLOYED"}];
221 let selectedItem = {label: "NOT DEPLOYED", value: "NOT DEPLOYED"};
222 if (typeof dataRow.supportedPdpGroups !== "undefined") {
223 for (const pdpGroup of dataRow["supportedPdpGroups"]) {
224 for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
225 optionItems.push({ label: Object.keys(pdpGroup)[0]+"/"+pdpSubGroup,
226 value: Object.keys(pdpGroup)[0]+"/"+pdpSubGroup });
227 }
228 }
229 }
230 if (typeof dataRow.pdpGroupInfo !== "undefined") {
231 selectedItem = {label: dataRow["pdpGroupInfo"]["pdpGroup"]+"/"+dataRow["pdpGroupInfo"]["pdpSubGroup"],
232 value: dataRow["pdpGroupInfo"]["pdpGroup"]+"/"+dataRow["pdpGroupInfo"]["pdpSubGroup"]};
233 }
234 return (<div style={{width: '250px'}}><Select value={selectedItem} options={optionItems} onChange={this.handlePdpGroupChange}/></div>);
235 }
236
237 getAllPolicies() {
238 PolicyService.getPoliciesList().then(allPolicies => {
239 this.setState({ policiesListData: allPolicies["policies"] })
240 });
241 }
242
243 handleClose() {
244 this.setState({ show: false });
245 this.props.history.push('/')
246 }
247
sebdet3718a162021-02-12 17:18:47 +0100248 handleOnRowClick(rowData) {
249 PolicyToscaService.getToscaPolicyModel(rowData["type"], rowData["type_version"]).then(respJsonPolicyTosca => {
250 this.setState({
sebdetc427e642021-02-17 17:53:17 +0100251 selectedRowId: rowData.tableData.id,
252 selectedRowIdJsonSchema: respJsonPolicyTosca,
253 selectedRowIdPolicyProperties: rowData["properties"],
sebdet3718a162021-02-12 17:18:47 +0100254 jsonEditorForPolicy: this.createJsonEditor(respJsonPolicyTosca, rowData["properties"])
255 });
256 });
257 }
258
sebdet37285472021-02-15 18:09:38 +0100259 handlePrefixGrouping(event) {
260 this.setState({prefixGrouping: event.target.checked});
sebdeta0a3a032021-02-16 14:53:43 +0100261 }
sebdet37285472021-02-15 18:09:38 +0100262
sebdeta0a3a032021-02-16 14:53:43 +0100263 handleDeletePolicy(event, rowData) {
sebdetea2969f2021-02-25 13:58:36 +0100264 PolicyService.deletePolicy(rowData["type"], rowData["type_version"], rowData["name"],rowData["version"]).then(
265 respPolicyDeletion => {
266 if (respPolicyDeletion === "") {
267 //it indicates a failure
268 this.setState({
269 showFailAlert: true,
270 showMessage: 'Policy Deletion Failure'
271 });
272 } else {
273 this.setState({
274 showSuccessAlert: true,
275 showMessage: 'Policy successfully Deleted'
276 });
277 }
278 }
279 )
sebdet37285472021-02-15 18:09:38 +0100280 }
281
sebdetc427e642021-02-17 17:53:17 +0100282 customValidation(editorData) {
283 // method for sub-classes to override with customized validation
284 return [];
285 }
286
287 handleCreateNewVersion() {
288 var editorData = this.state.jsonEditorForPolicy.getValue();
289 var errors = this.state.jsonEditorForPolicy.validate();
290 errors = errors.concat(this.customValidation(editorData));
291
292 if (errors.length !== 0) {
293 console.error("Errors detected during policy data validation ", errors);
294 this.setState({
295 showFailAlert: true,
296 showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
297 });
298 return;
299 } else {
300 console.info("NO validation errors found in policy data");
301 let newPolicy = JSON.parse(JSON.stringify(this.state.policiesListData[this.state.selectedRowId]));
302 newPolicy["properties"] = editorData;
303 let newVersion = this.bumpVersion(newPolicy["version"]);
304 newPolicy["version"] = newVersion;
305 newPolicy["metadata"]["policy-version"] = newVersion;
306 // Remove stuff added by UI
307 delete newPolicy["tableData"];
308 PolicyService.createNewPolicy(newPolicy["type"], newPolicy["type_version"], newPolicy).then(respPolicyCreation => {
309 if (respPolicyCreation === "") {
310 //it indicates a failure
311 this.setState({
312 showFailAlert: true,
313 showMessage: 'Policy Creation Failure'
314 });
315 } else {
316 this.setState({
317 showSuccessAlert: true,
318 showMessage: 'Policy in version ' + newVersion + ' created successfully'
319 });
320 }
321 })
322 }
323 }
324
325 bumpVersion(versionToBump) {
326 let semVer = versionToBump.split(".");
327 return parseInt(semVer[0])+1 + "." + semVer[1] + "." + semVer[2];
sebdeta0a3a032021-02-16 14:53:43 +0100328 }
329
330 handleUpdatePolicy() {
331 this.setState({ show: false });
332 this.props.history.push('/')
333 }
334
sebdetc427e642021-02-17 17:53:17 +0100335 disableAlert() {
336 this.setState ({ showSuccessAlert: false, showFailAlert: false });
337 }
338
sebdeteb8e3f12021-01-24 18:12:36 +0100339 render() {
340 return (
sebdet37285472021-02-15 18:09:38 +0100341 <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}>
sebdeteb8e3f12021-01-24 18:12:36 +0100342 <Modal.Header closeButton>
343 </Modal.Header>
sebdetea2969f2021-02-25 13:58:36 +0100344 <Tabs id="controlled-tab-example" activeKey={this.state.key} onSelect={key => this.setState({ key, selectedRowData: {} })}>
345 <Tab eventKey="policies" title="Policies in Policy Framework">
346 <Modal.Body>
347 <FormControlLabel
348 control={<Switch checked={this.state.prefixGrouping} onChange={this.handlePrefixGrouping} />}
349 label="Group by prefix"
350 />
351 <MaterialTable
352 title={"View All Policies in Policy Engine"}
353 data={this.state.policiesListData}
354 columns={this.state.policyColumnsDefinition}
355 icons={this.state.tableIcons}
356 onRowClick={(event, rowData) => {this.handleOnRowClick(rowData)}}
357 options={{
358 grouping: true,
359 exportButton: true,
360 headerStyle:rowHeaderStyle,
361 rowStyle: rowData => ({
362 backgroundColor: (this.state.selectedRowId !== -1 && this.state.selectedRowId === rowData.tableData.id) ? '#EEE' : '#FFF'
363 })
364 }}
365 actions={[
366 {
367 icon: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
368 tooltip: 'Delete Policy',
369 onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
370 }
371 ]}
372 />
373 </Modal.Body>
374 </Tab>
375 </Tabs>
sebdet37285472021-02-15 18:09:38 +0100376 <JsonEditorDiv>
377 <h5>Policy Properties Editor</h5>
378 <div id="policy-editor" title="Policy Properties"/>
sebdetc427e642021-02-17 17:53:17 +0100379 <Button variant="secondary" title="Create a new policy version from the defined parameters"
380 onClick={this.handleCreateNewVersion}>Create New Version</Button>
sebdet37285472021-02-15 18:09:38 +0100381 </JsonEditorDiv>
sebdetc427e642021-02-17 17:53:17 +0100382 <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible>
sebdetea2969f2021-02-25 13:58:36 +0100383 <DivWhiteSpaceStyled>
384 {this.state.showMessage}
385 </DivWhiteSpaceStyled>
386 </Alert>
387 <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible>
388 <DivWhiteSpaceStyled>
389 {this.state.showMessage}
390 </DivWhiteSpaceStyled>
391 </Alert>
sebdeteb8e3f12021-01-24 18:12:36 +0100392 <Modal.Footer>
393 <Button variant="secondary" onClick={this.handleClose}>Close</Button>
394 </Modal.Footer>
395 </ModalStyled>
396 );
397 }
398 }