0aed5f40040ef6a98b6376d6e33903d4b9b40af9
[policy/gui.git] / gui-clamp / ui-react / src / components / dialogs / Policy / ViewAllPolicies.js
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP POLICY-CLAMP
4  * ================================================================================
5  * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2022 Nordix Foundation.
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, { forwardRef } from 'react'
25 import Button from 'react-bootstrap/Button';
26 import Modal from 'react-bootstrap/Modal';
27 import styled from 'styled-components';
28 import AddBox from '@material-ui/icons/AddBox';
29 import ArrowDownward from '@material-ui/icons/ArrowDownward';
30 import Check from '@material-ui/icons/Check';
31 import ChevronLeft from '@material-ui/icons/ChevronLeft';
32 import ChevronRight from '@material-ui/icons/ChevronRight';
33 import Clear from '@material-ui/icons/Clear';
34 import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded';
35 import Edit from '@material-ui/icons/Edit';
36 import FilterList from '@material-ui/icons/FilterList';
37 import FirstPage from '@material-ui/icons/FirstPage';
38 import LastPage from '@material-ui/icons/LastPage';
39 import Remove from '@material-ui/icons/Remove';
40 import SaveAlt from '@material-ui/icons/SaveAlt';
41 import Search from '@material-ui/icons/Search';
42 import ViewColumn from '@material-ui/icons/ViewColumn';
43 import DehazeIcon from '@material-ui/icons/Dehaze';
44 import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
45 import AddIcon from '@material-ui/icons/Add';
46 import PublishIcon from '@material-ui/icons/Publish';
47 import MaterialTable from "material-table";
48 import PolicyService from '../../../api/PolicyService';
49 import PolicyToscaService from '../../../api/PolicyToscaService';
50 import Alert from 'react-bootstrap/Alert';
51 import Tabs from 'react-bootstrap/Tabs';
52 import Tab from 'react-bootstrap/Tab';
53 import PolicyEditor from './PolicyEditor';
54 import ToscaViewer from './ToscaViewer';
55 import PolicyDeploymentEditor from './PolicyDeploymentEditor';
56 import PoliciesTreeViewer from './PoliciesTreeViewer';
57 import PolicyToscaFileSelector from './PolicyToscaFileSelector';
58
59 const DivWhiteSpaceStyled = styled.div`
60   white-space: pre;
61 `
62
63 const ModalStyled = styled(Modal)`
64   @media (min-width: 800px) {
65     .modal-xl {
66       max-width: 96%;
67     }
68   }
69   background-color: transparent;
70 `
71 const DetailedRow = styled.div`
72   margin: 0 auto;
73   background-color: ${ props => props.theme.policyEditorBackgroundColor };
74   font-size: ${ props => props.theme.policyEditorFontSize };
75   width: 97%;
76   margin-left: auto;
77   margin-right: auto;
78   margin-top: 20px;
79 `
80
81 const PoliciesTreeViewerDiv = styled.div`
82   width: 20%;
83   float: left;
84   left: 0;
85   overflow: auto;
86 `
87
88 const MaterialTableDiv = styled.div`
89   float: right;
90   width: 80%;
91   left: 20%;
92 `
93
94 const standardCellStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' };
95 const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
96 const rowHeaderStyle = { backgroundColor: '#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black' };
97
98 export default class ViewAllPolicies extends React.Component {
99   state = {
100     show: true,
101     policiesListData: [],
102     policiesListDataFiltered: [],
103     toscaModelsListData: [],
104     toscaModelsListDataFiltered: [],
105     jsonEditorForPolicy: new Map(),
106     showSuccessAlert: false,
107     showFailAlert: false,
108     showFileSelector: false,
109     policyColumnsDefinition: [
110       {
111         title: "Policy Name", field: "name",
112         cellStyle: standardCellStyle,
113         headerStyle: headerStyle
114       },
115       {
116         title: "Policy Version", field: "version",
117         cellStyle: standardCellStyle,
118         headerStyle: headerStyle,
119       },
120       {
121         title: "Policy Type", field: "type",
122         cellStyle: standardCellStyle,
123         headerStyle: headerStyle
124       },
125       {
126         title: "Policy Type Version", field: "type_version",
127         cellStyle: standardCellStyle,
128         headerStyle: headerStyle
129       },
130       {
131         title: "Deployable in PDP Group", field: "supportedPdpGroupsString",
132         cellStyle: standardCellStyle,
133         headerStyle: headerStyle
134       },
135       {
136         title: "Deployed in PDP Group", field: "pdpGroupInfoString",
137         cellStyle: standardCellStyle,
138         headerStyle: headerStyle
139       }
140     ],
141     toscaColumnsDefinition: [
142       {
143         title: "Policy Model Type", field: "policyModelType",
144         cellStyle: standardCellStyle,
145         headerStyle: headerStyle
146       },
147       {
148         title: "Policy Acronym", field: "policyAcronym",
149         cellStyle: standardCellStyle,
150         headerStyle: headerStyle
151       },
152       {
153         title: "Version", field: "version",
154         cellStyle: standardCellStyle,
155         headerStyle: headerStyle
156       },
157       {
158         title: "Uploaded By", field: "updatedBy",
159         cellStyle: standardCellStyle,
160         headerStyle: headerStyle
161       },
162       {
163         title: "Uploaded Date", field: "updatedDate", editable: 'never',
164         cellStyle: standardCellStyle,
165         headerStyle: headerStyle
166       }
167     ],
168     tableIcons: {
169       Add: forwardRef((props, ref) => <AddBox { ...props } ref={ ref }/>),
170       Check: forwardRef((props, ref) => <Check { ...props } ref={ ref }/>),
171       Clear: forwardRef((props, ref) => <Clear { ...props } ref={ ref }/>),
172       Delete: forwardRef((props, ref) => <DeleteRoundedIcon { ...props } ref={ ref }/>),
173       DetailPanel: forwardRef((props, ref) => <ChevronRight { ...props } ref={ ref }/>),
174       Edit: forwardRef((props, ref) => <Edit { ...props } ref={ ref }/>),
175       Export: forwardRef((props, ref) => <SaveAlt { ...props } ref={ ref }/>),
176       Filter: forwardRef((props, ref) => <FilterList { ...props } ref={ ref }/>),
177       FirstPage: forwardRef((props, ref) => <FirstPage { ...props } ref={ ref }/>),
178       LastPage: forwardRef((props, ref) => <LastPage { ...props } ref={ ref }/>),
179       NextPage: forwardRef((props, ref) => <ChevronRight { ...props } ref={ ref }/>),
180       PreviousPage: forwardRef((props, ref) => <ChevronLeft { ...props } ref={ ref }/>),
181       ResetSearch: forwardRef((props, ref) => <Clear { ...props } ref={ ref }/>),
182       Search: forwardRef((props, ref) => <Search { ...props } ref={ ref }/>),
183       SortArrow: forwardRef((props, ref) => <ArrowDownward { ...props } ref={ ref }/>),
184       ThirdStateCheck: forwardRef((props, ref) => <Remove { ...props } ref={ ref }/>),
185       ViewColumn: forwardRef((props, ref) => <ViewColumn { ...props } ref={ ref }/>)
186     }
187   };
188
189   constructor(props, context) {
190     super(props, context);
191     this.handleClose = this.handleClose.bind(this);
192     this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
193     this.disableAlert = this.disableAlert.bind(this);
194     this.getAllPolicies = this.getAllPolicies.bind(this);
195     this.getAllToscaModels = this.getAllToscaModels.bind(this);
196     this.generateAdditionalPolicyColumns = this.generateAdditionalPolicyColumns.bind(this);
197     this.filterPolicies = this.filterPolicies.bind(this);
198     this.filterTosca = this.filterTosca.bind(this);
199     this.showFileSelector = this.showFileSelector.bind(this);
200     this.disableFileSelector = this.disableFileSelector.bind(this);
201     this.getAllPolicies();
202     this.getAllToscaModels();
203   }
204
205   generateAdditionalPolicyColumns(policiesData) {
206     policiesData.forEach(policy => {
207       let supportedPdpGroupsString = "";
208       if (typeof policy.supportedPdpGroups !== "undefined") {
209         for (const pdpGroup of policy["supportedPdpGroups"]) {
210           for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
211             supportedPdpGroupsString += (Object.keys(pdpGroup)[0] + "/" + pdpSubGroup + "\r\n");
212           }
213         }
214         policy["supportedPdpGroupsString"] = supportedPdpGroupsString;
215       }
216
217       let infoPdpGroup = "";
218       if (typeof policy.pdpGroupInfo !== "undefined") {
219         policy["pdpGroupInfo"].forEach(pdpGroupElem => {
220           let groupName = Object.keys(pdpGroupElem)[0];
221           pdpGroupElem[groupName]["pdpSubgroups"].forEach(pdpSubGroupElem => {
222             infoPdpGroup += (groupName + "/" + pdpSubGroupElem["pdpType"] + " ("
223               + pdpGroupElem[groupName]["pdpGroupState"] + ")" + "\r\n");
224           });
225           policy["pdpGroupInfoString"] = infoPdpGroup;
226         });
227       }
228     });
229   }
230
231   getAllToscaModels() {
232     PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => {
233       this.setState({
234         toscaModelsListData: toscaModelsList,
235         toscaModelsListDataFiltered: toscaModelsList
236       });
237     });
238   }
239
240   getAllPolicies() {
241     PolicyService.getPoliciesList().then(allPolicies => {
242       this.generateAdditionalPolicyColumns(allPolicies["policies"])
243       this.setState({
244         policiesListData: allPolicies["policies"],
245         policiesListDataFiltered: allPolicies["policies"],
246       })
247     });
248
249   }
250
251   handleClose() {
252     console.log("handleClose called");
253     this.setState({ show: false });
254     this.props.history.push('/')
255   }
256
257   handleDeletePolicy(event, rowData) {
258     PolicyService.deletePolicy(rowData["type"], rowData["type_version"], rowData["name"], rowData["version"]).then(
259       respPolicyDeletion => {
260         if (typeof (respPolicyDeletion) === "undefined") {
261           //it indicates a failure
262           this.setState({
263             showFailAlert: true,
264             showMessage: 'Policy Deletion Failure'
265           });
266         } else {
267           this.setState({
268             showSuccessAlert: true,
269             showMessage: 'Policy successfully Deleted'
270           });
271           this.getAllPolicies();
272         }
273       }
274     )
275   }
276
277   disableAlert() {
278     this.setState({ showSuccessAlert: false, showFailAlert: false });
279   }
280
281   filterPolicies(prefixForFiltering) {
282     this.setState({ policiesListDataFiltered: this.state.policiesListData.filter(element => element.name.startsWith(prefixForFiltering)) });
283   }
284
285   filterTosca(prefixForFiltering) {
286     this.setState({ toscaModelsListDataFiltered: this.state.toscaModelsListData.filter(element => element.policyModelType.startsWith(prefixForFiltering)) });
287   }
288
289   showFileSelector() {
290     this.setState({ showFileSelector: true });
291   }
292
293   disableFileSelector() {
294     this.setState({ showFileSelector: false });
295   }
296
297   renderPoliciesTab() {
298     return (
299       <Tab eventKey="policies" title="Policies in Policy Framework">
300         <Modal.Body>
301           <div>
302             <PoliciesTreeViewerDiv>
303               <PoliciesTreeViewer policiesData={ this.state.policiesListData } valueForTreeCreation="name" policiesFilterFunction={ this.filterPolicies }/>
304             </PoliciesTreeViewerDiv>
305             <MaterialTableDiv>
306               <MaterialTable
307                 title={ "Policies" }
308                 data={ this.state.policiesListDataFiltered }
309                 columns={ this.state.policyColumnsDefinition }
310                 icons={ this.state.tableIcons }
311                 onRowClick={ (event, rowData, togglePanel) => togglePanel() }
312                 options={ {
313                   grouping: true,
314                   exportButton: true,
315                   headerStyle: rowHeaderStyle,
316                   actionsColumnIndex: -1
317                 } }
318                 detailPanel={ [
319                   {
320                     icon: ArrowForwardIosIcon,
321                     tooltip: 'Show Configuration',
322                     render: rowData => {
323                       return (
324                         <DetailedRow>
325                           <PolicyEditor policyModelType={ rowData["type"] } policyModelTypeVersion={ rowData["type_version"] }
326                                         policyName={ rowData["name"] } policyVersion={ rowData["version"] } policyProperties={ rowData["properties"] }
327                                         policiesTableUpdateFunction={ this.getAllPolicies }/>
328                         </DetailedRow>
329                       )
330                     },
331                   },
332                   {
333                     icon: DehazeIcon,
334                     openIcon: DehazeIcon,
335                     tooltip: 'Show Raw Data',
336                     render: rowData => {
337                       return (
338                         <DetailedRow>
339                           <pre>{ JSON.stringify(rowData, null, 2) }</pre>
340                         </DetailedRow>
341                       )
342                     },
343                   },
344                   {
345                     icon: PublishIcon,
346                     openIcon: PublishIcon,
347                     tooltip: 'PDP Group Deployment',
348                     render: rowData => {
349                       return (
350                         <DetailedRow>
351                           <PolicyDeploymentEditor policyData={ rowData } policiesTableUpdateFunction={ this.getAllPolicies }/>
352                         </DetailedRow>
353                       )
354                     },
355                   }
356                 ] }
357                 actions={ [
358                   {
359                     icon: DeleteRoundedIcon,
360                     tooltip: 'Delete Policy',
361                     onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
362                   }
363                 ] }
364               />
365             </MaterialTableDiv>
366           </div>
367         </Modal.Body>
368       </Tab>
369     );
370   }
371
372   renderToscaTab() {
373     return (
374       <Tab eventKey="tosca models" title="Tosca Models in Policy Framework">
375         <Modal.Body>
376           <div>
377             <PoliciesTreeViewerDiv>
378               <PoliciesTreeViewer policiesData={ this.state.toscaModelsListData } valueForTreeCreation="policyModelType" policiesFilterFunction={ this.filterTosca }/>
379             </PoliciesTreeViewerDiv>
380             <MaterialTableDiv>
381               <MaterialTable
382                 title={ "Tosca Models" }
383                 data={ this.state.toscaModelsListDataFiltered }
384                 columns={ this.state.toscaColumnsDefinition }
385                 icons={ this.state.tableIcons }
386                 onRowClick={ (event, rowData, togglePanel) => togglePanel() }
387                 options={ {
388                   grouping: true,
389                   exportButton: true,
390                   headerStyle: rowHeaderStyle,
391                   actionsColumnIndex: -1
392                 } }
393                 actions={ [
394                   {
395                     icon: AddIcon,
396                     tooltip: 'Add New Tosca Model',
397                     isFreeAction: true,
398                     onClick: () => this.showFileSelector()
399                   }
400                 ] }
401                 detailPanel={ [
402                   {
403                     icon: ArrowForwardIosIcon,
404                     tooltip: 'Show Tosca',
405                     render: rowData => {
406                       return (
407                         <DetailedRow>
408                           <ToscaViewer toscaData={ rowData }/>
409                         </DetailedRow>
410                       )
411                     },
412                   },
413                   {
414                     icon: DehazeIcon,
415                     openIcon: DehazeIcon,
416                     tooltip: 'Show Raw Data',
417                     render: rowData => {
418                       return (
419                         <DetailedRow>
420                           <pre>{ JSON.stringify(rowData, null, 2) }</pre>
421                         </DetailedRow>
422                       )
423                     },
424                   },
425                   {
426                     icon: AddIcon,
427                     openIcon: AddIcon,
428                     tooltip: 'Create a policy from this model',
429                     render: rowData => {
430                       return (
431                         <DetailedRow>
432                           <PolicyEditor policyModelType={ rowData["policyModelType"] } policyModelTypeVersion={ rowData["version"] } policyProperties={ {} } policiesTableUpdateFunction={ this.getAllPolicies }/>
433                         </DetailedRow>
434                       )
435                     },
436                   },
437                 ] }
438               />
439             </MaterialTableDiv>
440           </div>
441         </Modal.Body>
442       </Tab>
443     );
444   }
445
446   render() {
447     return (
448       <React.Fragment>
449         <ModalStyled size="xl" show={ this.state.show } onHide={ this.handleClose } backdrop="static" keyboard={ false }>
450           <Modal.Header closeButton>
451           </Modal.Header>
452           <Tabs id="controlled-tab-example" activeKey={ this.state.key } onSelect={ key => this.setState({ key, selectedRowData: {} }) }>
453             { this.renderPoliciesTab() }
454             { this.renderToscaTab() }
455           </Tabs>
456           <Alert variant="success" show={ this.state.showSuccessAlert } onClose={ this.disableAlert } dismissible>
457             <DivWhiteSpaceStyled>
458               { this.state.showMessage }
459             </DivWhiteSpaceStyled>
460           </Alert>
461           <Alert variant="danger" show={ this.state.showFailAlert } onClose={ this.disableAlert } dismissible>
462             <DivWhiteSpaceStyled>
463               { this.state.showMessage }
464             </DivWhiteSpaceStyled>
465           </Alert>
466           <Modal.Footer>
467             <Button variant="secondary" onClick={ this.handleClose }>Close</Button>
468           </Modal.Footer>
469         </ModalStyled>
470         <PolicyToscaFileSelector show={ this.state.showFileSelector } disableFunction={ this.disableFileSelector } toscaTableUpdateFunction={ this.getAllToscaModels }/>
471       </React.Fragment>
472     );
473   }
474 }