From 8c6beedc3d58420988c9e80d75aad96198e2962e Mon Sep 17 00:00:00 2001 From: brunomilitzer Date: Fri, 4 Jun 2021 14:40:46 +0100 Subject: MERGE Clamp UI-React repo to Policy Gui Repo According to a Diff differences from one repo to the other, there was some missing changes from the original clamp repo to the policy gui repo. Issue-ID: POLICY-3267 Change-Id: I9a71841732dc5c3d9623bca9c1384866f4c826a6 Signed-off-by: brunomilitzer --- gui-clamp/ui-react/package.json | 18 +- gui-clamp/ui-react/src/api/PoliciesListCache.js | 34 - gui-clamp/ui-react/src/api/PolicyService.js | 56 +- gui-clamp/ui-react/src/api/PolicyToscaService.js | 56 -- .../dialogs/Loop/CreateLoopModal.test.js | 7 + .../src/components/dialogs/Loop/DeployLoopModal.js | 21 +- .../src/components/dialogs/Loop/ModifyLoopModal.js | 7 - .../__snapshots__/DeployLoopModal.test.js.snap | 9 +- .../dialogs/Policy/PoliciesTreeViewer.js | 109 +++ .../dialogs/Policy/PolicyDeploymentEditor.js | 178 +++++ .../src/components/dialogs/Policy/PolicyEditor.js | 29 +- .../components/dialogs/Policy/PolicyEditor.test.js | 72 ++ .../src/components/dialogs/Policy/PolicyModal.js | 21 +- .../components/dialogs/Policy/PolicyModal.test.js | 11 +- .../dialogs/Policy/PolicyToscaFileSelector.js | 133 ++++ .../src/components/dialogs/Policy/ToscaViewer.js | 7 +- .../components/dialogs/Policy/ToscaViewer.test.js | 54 ++ .../components/dialogs/Policy/ViewAllPolicies.js | 434 +++++++----- .../Policy/__snapshots__/PolicyEditor.test.js.snap | 788 +++++++++++++++++++++ .../Policy/__snapshots__/PolicyModal.test.js.snap | 159 +++++ .../Policy/__snapshots__/ToscaViewer.test.js.snap | 30 + .../components/dialogs/Policy/toscaData.test.json | 179 +++++ .../components/dialogs/Policy/toscaData.test.yaml | 13 + .../dialogs/Tosca/ViewLoopTemplatesModal.js | 4 +- .../src/components/dialogs/UserInfoModal.js | 2 +- .../__snapshots__/UserInfoModal.test.js.snap | 2 + .../src/components/loop_viewer/logs/LoopLogs.js | 7 +- .../logs/__snapshots__/LoopLogs.test.js.snap | 1 + .../components/loop_viewer/status/LoopStatus.js | 7 +- .../status/__snapshots__/LoopStatus.test.js.snap | 2 + .../src/components/loop_viewer/svg/SvgGenerator.js | 388 +++++----- gui-clamp/ui-react/src/setupTests.js | 4 +- 32 files changed, 2272 insertions(+), 570 deletions(-) delete mode 100644 gui-clamp/ui-react/src/api/PoliciesListCache.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json create mode 100644 gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml (limited to 'gui-clamp/ui-react') diff --git a/gui-clamp/ui-react/package.json b/gui-clamp/ui-react/package.json index 8d11044..fd3dc0a 100644 --- a/gui-clamp/ui-react/package.json +++ b/gui-clamp/ui-react/package.json @@ -27,8 +27,8 @@ "dependencies": { "@json-editor/json-editor": "2.5.2", "@fortawesome/fontawesome-free": "5.15.2", - "react": "17.0.1", - "react-dom": "17.0.1", + "react": "17.0.2", + "react-dom": "17.0.2", "react-scripts": "4.0.3", "react-bootstrap": "1.5.2", "bootstrap-css-only": "4.3.1", @@ -36,9 +36,10 @@ "react-router-dom": "5.2.0", "@material-ui/core": "4.11.3", "@material-ui/icons": "4.11.2", + "@material-ui/pickers": "3.3.10", + "@material-ui/lab": "4.0.0-alpha.57", "material-table": "1.68.1", - "react-select": "4.2.1", - "react-uuid": "1.0.2" + "react-select": "4.2.1" }, "devDependencies": { "jest": "26.6.0", @@ -47,9 +48,10 @@ "@babel/preset-react": "7.12.13", "@babel/plugin-proposal-class-properties": "7.13.0", "enzyme": "3.11.0", - "enzyme-adapter-react-17-updated": "1.0.2", + "@wojtekmaj/enzyme-adapter-react-17": "0.6.1", "enzyme-to-json": "3.6.1", - "jest-fetch-mock": "3.0.3" + "jest-fetch-mock": "3.0.3", + "jest-canvas-mock": "2.3.1" }, "browserslist": [ ">0.2%", @@ -71,7 +73,8 @@ "\\.(css|png)$": "identity-obj-proxy" }, "setupFiles": [ - "./src/setupTests.js" + "./src/setupTests.js", + "jest-canvas-mock" ], "snapshotSerializers": [ "enzyme-to-json/serializer" @@ -95,4 +98,3 @@ ] } } - diff --git a/gui-clamp/ui-react/src/api/PoliciesListCache.js b/gui-clamp/ui-react/src/api/PoliciesListCache.js deleted file mode 100644 index 265dab4..0000000 --- a/gui-clamp/ui-react/src/api/PoliciesListCache.js +++ /dev/null @@ -1,34 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP CLAMP - * ================================================================================ - * Copyright (C) 2021 AT&T Intellectual Property. All rights - * reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END============================================ - * =================================================================== - * - */ - -export default class PoliciesListCache { - policiesJsonCache; - - constructor(policiesJson) { - this.policiesJsonCache = policiesJson; - } - - getAllPolicies() { - return this.policiesJsonCache["policies"]; - } -} diff --git a/gui-clamp/ui-react/src/api/PolicyService.js b/gui-clamp/ui-react/src/api/PolicyService.js index 046f789..cf4f0fd 100644 --- a/gui-clamp/ui-react/src/api/PolicyService.js +++ b/gui-clamp/ui-react/src/api/PolicyService.js @@ -41,7 +41,7 @@ export default class PolicyService { console.error("getPoliciesList error occurred ", error); alert("getPoliciesList error occurred " + error); return undefined; - }) + }); } static createNewPolicy(policyModelType, policyModelVersion, policyName, policyVersion, policyJson) { @@ -95,4 +95,58 @@ export default class PolicyService { return undefined; }); } + + static updatePdpDeployment(pdpOperationsList) { + return fetch(window.location.pathname + 'restservices/clds/v2/policies/pdpDeployment', { + method: 'PUT', + credentials: 'same-origin', + headers: { + "Content-Type": "application/json" + }, + body: JSON.stringify(pdpOperationsList) + }) + .then(function (response) { + console.debug("updatePdpDeployment response received: ", response.status); + if (response.ok) { + console.info("updatePdpDeployment query successful"); + return response.text(); + } else { + return response.text().then(responseBody => { + throw new Error("HTTP " + response.status + "," + responseBody); + }) + } + }) + .catch(function (error) { + console.error("updatePdpDeployment error occurred ", error); + alert("updatePdpDeployment error occurred " + error); + return undefined; + }); + } + + static sendNewPolicyModel(newPolicyModel) { + return fetch(window.location.pathname + 'restservices/clds/v2/policies/policytype', { + method: 'POST', + credentials: 'same-origin', + headers: { + "Content-Type": "plain/text" + }, + body: newPolicyModel + }) + .then(function (response) { + console.debug("sendNewPolicyModel response received: ", response.status); + if (response.ok) { + console.info("sendNewPolicyModel query successful"); + return response.text(); + } else { + return response.text().then(responseBody => { + throw new Error("HTTP " + response.status + "," + responseBody); + }) + } + }) + .catch(function (error) { + console.error("sendNewPolicyModel error occurred ", error); + alert("sendNewPolicyModel error occurred " + error); + return undefined; + }); + } } diff --git a/gui-clamp/ui-react/src/api/PolicyToscaService.js b/gui-clamp/ui-react/src/api/PolicyToscaService.js index b5282f9..6c74149 100644 --- a/gui-clamp/ui-react/src/api/PolicyToscaService.js +++ b/gui-clamp/ui-react/src/api/PolicyToscaService.js @@ -77,60 +77,4 @@ export default class PolicyToscaService { return {}; }); } - - static createPolicyModelFromToscaModel(jsonData) { - return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels', { - method: 'POST', - credentials: 'same-origin', - headers: { - "Content-Type": "a", - }, - body: JSON.stringify(jsonData) - }) - .then(function (response) { - console.debug("createPolicyModelFromToscaModel response received: ", response.status); - if (response.ok) { - var message = { - status: response.status, - message: 'Tosca Policy Model successfully uploaded' - }; - return message; - } else { - console.error("createPolicyModelFromToscaModel failed"); - return response.text(); - } - }) - .catch(function (error) { - console.error("createPolicyModelFromToscaModel error received", error); - return ""; - }); - } - - static updatePolicyModelTosca(policyModelType, policyModelVersion, jsonData) { - return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels/' + policyModelType + '/' + policyModelVersion, { - method: 'PUT', - credentials: 'same-origin', - headers: { - "Content-Type": "a", - }, - body: JSON.stringify(jsonData) - }) - .then(function (response) { - console.debug("updatePolicyModelTosca response received: ", response.status); - if (response.ok) { - var message = { - status: response.status, - message: 'Tosca Policy Model successfully uploaded' - }; - return message; - } else { - console.error("updatePolicyModelTosca failed"); - return response.text(); - } - }) - .catch(function (error) { - console.error("updatePolicyModelTosca error received", error); - return ""; - }); - } } diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js b/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js index 401bb6a..3d94833 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js +++ b/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js @@ -26,6 +26,13 @@ import CreateLoopModal from './CreateLoopModal'; import LoopService from '../../../api/LoopService'; import TemplateService from '../../../api/TemplateService'; +let errorMessage = ''; +window.alert = jest.fn().mockImplementation((mesg) => { + errorMessage = mesg; + return +}); + + describe('Verify CreateLoopModal', () => { it('Test the render method', async () => { diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js b/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js index b7ab8a5..5fff586 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * ONAP CLAMP + * ONAP POLICY-CLAMP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights * reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,6 +44,7 @@ const FormStyled = styled(Form.Group)` ` export default class DeployLoopModal extends React.Component { + constructor(props, context) { super(props, context); @@ -65,13 +66,7 @@ export default class DeployLoopModal extends React.Component { getInitialKeyValue(temporaryPropertiesJson) { const deployJsonList = temporaryPropertiesJson["dcaeDeployParameters"]; - let initialKey; - Object.keys(deployJsonList) - .filter((obj) => Object.keys(deployJsonList).indexOf(obj) === 0) - .map(obj => - initialKey = obj - ); - return initialKey; + return Object.keys(deployJsonList).find((obj) => Object.keys(deployJsonList).indexOf(obj) === 0); } componentWillReceiveProps(newProps) { @@ -145,8 +140,8 @@ export default class DeployLoopModal extends React.Component { const deployJsonList = this.state.temporaryPropertiesJson["dcaeDeployParameters"]; var indents = []; - Object.keys(deployJsonList).map((item, key) => - indents.push( + Object.keys(deployJsonList).forEach(item => + indents.push( { this.renderDeployParam(deployJsonList[item]) } ) ); @@ -155,8 +150,8 @@ export default class DeployLoopModal extends React.Component { renderDeployParam(deployJson) { var indents = []; - Object.keys(deployJson).map((item, key) => - indents.push( + Object.keys(deployJson).forEach(item => + indents.push( { item } )); diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js b/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js index 8f8b74d..0d20341 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js @@ -130,13 +130,6 @@ export default class ModifyLoopModal extends React.Component { this.initializeToscaPolicyModelsInfo(); } - componentWillReceiveProps(newProps) { - this.setState({ - loopCache: newProps.loopCache, - temporaryPropertiesJson: JSON.parse(JSON.stringify(newProps.loopCache.getGlobalProperties())) - }); - } - initializeToscaPolicyModelsInfo() { var operationalPolicies = this.state.loopCache.getOperationalPolicies(); var selectedPolicyModels = []; diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap index 4779ced..33f8faa 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap +++ b/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap @@ -26,9 +26,12 @@ exports[`Verify DeployLoopModal Test the render method 1`] = ` > - + - + { + let currentTreeNode = root; + policy[this.props.valueForTreeCreation].split(this.separator).forEach((policyNamePart, index, policyNamePartsArray) => { + let node = currentTreeNode["children"].find(element => element.name === policyNamePart); + if (typeof (node) === "undefined") { + node = { id: nodeId, policyCount: 0, children: [], name: policyNamePart, parent: currentTreeNode }; + this.nodesList.set(nodeId++, node); + currentTreeNode["children"].push(node); + } + if ((index + 1) === policyNamePartsArray.length) { + ++currentTreeNode["policyCount"]; + } + currentTreeNode = node; + }) + }) + return root; + } + + buildNameWithParent(node) { + let nameToBuild = node.name; + if (node.parent !== undefined) { + nameToBuild = this.buildNameWithParent(node.parent) + this.separator + node.name; + } + return nameToBuild; + } + + handleTreeItemClick(event, value) { + let fullName = this.buildNameWithParent(this.nodesList.get(value[0])).substring(5); + this.props.policiesFilterFunction(fullName); + } + + renderTreeItems(nodes) { + return ( + { + Array.isArray(nodes.children) ? nodes.children.map((node) => this.renderTreeItems(node)) : null + } + ); + }; + + render() { + return ( + } + defaultExpandIcon={ } defaultEndIcon={ } onNodeSelect={ this.handleTreeItemClick } multiSelect> + { this.renderTreeItems(this.state.policiesTreeData) } + + ); + } +} diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js new file mode 100644 index 0000000..de29947 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js @@ -0,0 +1,178 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ + +import React, { forwardRef } from 'react'; +import Modal from 'react-bootstrap/Modal'; +import styled from 'styled-components'; +import Button from 'react-bootstrap/Button'; +import Alert from 'react-bootstrap/Alert'; +import PolicyService from '../../../api/PolicyService'; +import FormGroup from '@material-ui/core/FormGroup'; +import Checkbox from '@material-ui/core/Checkbox'; +import FormControlLabel from '@material-ui/core/FormControlLabel'; + +const DivWhiteSpaceStyled = styled.div` + white-space: pre; +` + +const PanelDiv = styled.div` + text-align: justify; + font-size: ${ props => props.theme.policyEditorFontSize }; + background-color: ${ props => props.theme.loopViewerBackgroundColor }; +` + +export default class PolicyDeploymentEditor extends React.Component { + + state = { + policyData: this.props.policyData, + showSuccessAlert: false, + showFailAlert: false, + checkboxesState: this.createPdpStructure(this.props.policyData), + checkboxesInitialState: this.createPdpStructure(this.props.policyData), + }; + + constructor(props, context) { + super(props, context); + this.handleClose = this.handleClose.bind(this); + this.handleUpdatePdpDeployment = this.handleUpdatePdpDeployment.bind(this); + this.disableAlert = this.disableAlert.bind(this); + this.renderPdpDeploymentCheckboxes = this.renderPdpDeploymentCheckboxes.bind(this); + this.createPdpStructure = this.createPdpStructure.bind(this); + this.handleCheckboxChange = this.handleCheckboxChange.bind(this); + this.createPdpGroupOperations = this.createPdpGroupOperations.bind(this); + } + + handleClose() { + this.setState({ show: false }); + + } + + disableAlert() { + this.setState({ showSuccessAlert: false, showFailAlert: false }); + } + + createPdpGroupOperations(initialStates, newStates) { + let commandsArray = []; + initialStates.forEach(initElem => { + let newStateFound = newStates.find(newElement => newElement.name === initElem.name); + if (initElem.value !== newStateFound.value) { + let newPdpGroupsArray = newStateFound.name.split("/"); + let operation = "POST/"; + if (initElem.value) { + operation = "DELETE/"; + } + commandsArray.push(operation + newPdpGroupsArray[0] + "/" + newPdpGroupsArray[1] + "/" + + this.state.policyData.name + "/" + this.state.policyData.version); + } + }); + return commandsArray.length > 0 ? { "PdpActions": commandsArray } : undefined; + } + + handleUpdatePdpDeployment() { + let operationsList = this.createPdpGroupOperations(this.state.checkboxesInitialState, + this.state.checkboxesState); + if (typeof (operationsList) !== "undefined") { + PolicyService.updatePdpDeployment(operationsList).then(respPdpDeploymentUpdate => { + if (typeof (respPdpDeploymentUpdate) === "undefined") { + //it indicates a failure + this.setState({ + showFailAlert: true, + showMessage: 'Pdp Deployment update Failure' + }); + } else { + this.setState({ + showSuccessAlert: true, + showMessage: 'Pdp Deployment Update successful' + }); + this.props.policiesTableUpdateFunction(); + } + }) + } else { + this.setState({ + showSuccessAlert: true, + showMessage: 'Pdp Deployment: Nothing to change' + }); + } + } + + createPdpStructure(policyData) { + // Create map with data for all group/subgroup where the policy is deployed + let infoPdpMap = new Map(); + if (typeof policyData.pdpGroupInfo !== "undefined") { + policyData["pdpGroupInfo"].forEach(pdpGroupElem => { + let pdpGroupName = Object.keys(pdpGroupElem)[0]; + pdpGroupElem[pdpGroupName]["pdpSubgroups"].forEach(pdpSubGroupElem => { + infoPdpMap.set(pdpGroupName + "/" + pdpSubGroupElem["pdpType"], true); + }); + }); + } + // Create the possible values for pdpgroup/subgroup and tick the ones where policy is deployed + let pdpStates = []; + if (typeof policyData.supportedPdpGroups !== "undefined") { + for (const pdpGroup of policyData["supportedPdpGroups"]) { + let pdpGroupName = Object.keys(pdpGroup)[0]; + for (const pdpSubGroup of Object.values(pdpGroup)[0]) { + let fullName = pdpGroupName + "/" + pdpSubGroup; + pdpStates.push({ + name: fullName, + value: infoPdpMap.get(fullName) !== undefined + }); + } + } + } + return pdpStates; + } + + handleCheckboxChange(event) { + const checkboxesArray = this.state.checkboxesState; + checkboxesArray.find(element => element.name === event.target.name).value = event.target.checked; + this.setState({ checkboxesState: checkboxesArray }); + } + + renderPdpDeploymentCheckboxes() { + return this.state.checkboxesState.map(item => { + return } label={ item.name }/>; + }); + } + + render() { + return ( + + + + { this.state.showMessage } + + + + + { this.state.showMessage } + + + + { this.renderPdpDeploymentCheckboxes() } + + ); + } +} diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js index 525d66b..1e27541 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js @@ -31,9 +31,7 @@ import TextField from '@material-ui/core/TextField'; import Alert from 'react-bootstrap/Alert'; import PolicyService from '../../../api/PolicyService'; import OnapUtils from '../../../utils/OnapUtils'; -import uuid from 'react-uuid'; -//const JSONEditor = require("@json-editor/json-editor").JSONEditor; const DivWhiteSpaceStyled = styled.div` white-space: pre; ` @@ -46,7 +44,6 @@ const JsonEditorDiv = styled.div` border: 1px solid #C0C0C0; ` const PanelDiv = styled.div` - margin-top: 20px; text-align: justify; font-size: ${ props => props.theme.policyEditorFontSize }; background-color: ${ props => props.theme.loopViewerBackgroundColor }; @@ -63,7 +60,7 @@ export default class PolicyEditor extends React.Component { showSuccessAlert: false, showFailAlert: false, jsonEditor: null, - jsonEditorDivId: uuid(), + jsonEditorDivId: this.props.policyModelType + "_" + this.props.policyModelTypeVersion + "_" + this.props.policyName + "_" + this.props.policyVersion, } constructor(props, context) { @@ -112,17 +109,12 @@ export default class PolicyEditor extends React.Component { showSuccessAlert: true, showMessage: 'Policy ' + this.state.policyName + '/' + this.state.policyVersion + ' created successfully' }); - this.props.policyUpdateFunction(); + this.props.policiesTableUpdateFunction(); } }) } } - bumpVersion(versionToBump) { - let semVer = versionToBump.split("."); - return parseInt(semVer[0]) + 1 + "." + semVer[1] + "." + semVer[2]; - } - getToscaModelForPolicy() { PolicyToscaService.getToscaPolicyModel(this.state.policyModelType, this.state.policyModelTypeVersion).then(respJsonPolicyTosca => { if (respJsonPolicyTosca !== {}) { @@ -139,27 +131,10 @@ export default class PolicyEditor extends React.Component { } createJsonEditor(toscaModel, editorData) { - /*JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({ - getTab: function(text,tabId) { - var liel = document.createElement('li'); - liel.classList.add('nav-item'); - var ael = document.createElement("a"); - ael.classList.add("nav-link"); - ael.setAttribute("style",'padding:10px;max-width:160px;'); - ael.setAttribute("href", "#" + tabId); - ael.setAttribute('data-toggle', 'tab'); - text.setAttribute("style",'word-wrap:break-word;'); - ael.appendChild(text); - liel.appendChild(ael); - return liel; - } - });*/ - return new JSONEditor(document.getElementById(this.state.jsonEditorDivId), { schema: toscaModel, startval: editorData, - //theme: 'myBootstrap4', theme: 'bootstrap4', iconlib: 'fontawesome5', object_layout: 'grid', diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js new file mode 100644 index 0000000..111f2c6 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js @@ -0,0 +1,72 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ +import React from 'react'; +import PolicyEditor from './PolicyEditor'; +import { shallow, mount } from 'enzyme'; +import PolicyToscaService from '../../../api/PolicyToscaService'; + +describe('Verify PolicyEditor', () => { + const fs = require('fs'); + + let toscaJson = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.json', { encoding: 'utf8', flag: 'r' }) + + const policyProperties = { + "tca.policy": { + "domain": "measurementsForVfScaling", + "metricsPerEventName": [ + { + "policyScope": "DCAE", + "thresholds": [ + { + "version": "1.0.2", + "severity": "MAJOR", + "thresholdValue": 200, + "closedLoopEventStatus": "ONSET", + "closedLoopControlName": "LOOP_test", + "direction": "LESS_OR_EQUAL", + "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta" + } + ], + "eventName": "vLoadBalancer", + "policyVersion": "v0.0.1", + "controlLoopSchemaType": "VM", + "policyName": "DCAE.Config_tca-hi-lo" + } + ] + } + }; + + + it('Test the render method', async () => { + PolicyToscaService.getToscaPolicyModel = jest.fn().mockImplementation(() => { + return Promise.resolve(toscaJson); + }); + + const component = mount( { + } }/>); + await PolicyToscaService.getToscaPolicyModel(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js index 105b2c5..0c7637c 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js @@ -137,21 +137,6 @@ export default class PolicyModal extends React.Component { } createJsonEditor(toscaModel, editorData) { - /*JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({ - getTab: function(text,tabId) { - var liel = document.createElement('li'); - liel.classList.add('nav-item'); - var ael = document.createElement("a"); - ael.classList.add("nav-link"); - ael.setAttribute("style",'padding:10px;max-width:160px;'); - ael.setAttribute("href", "#" + tabId); - ael.setAttribute('data-toggle', 'tab'); - text.setAttribute("style",'word-wrap:break-word;'); - ael.appendChild(text); - liel.appendChild(ael); - return liel; - } - });*/ return new JSONEditor(document.getElementById("editor"), { schema: toscaModel, @@ -316,17 +301,17 @@ export default class PolicyModal extends React.Component { } renderButton() { - var allElement = [()]; if (this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) { allElement.push(( - )); allElement.push(( - )); diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js index 734f22e..658b19e 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * ONAP CLAMP + * ONAP POLICY-CLAMP * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights + * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights * reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import PolicyModal from './PolicyModal'; import LoopCache from '../../../api/LoopCache'; import LoopService from '../../../api/LoopService'; import OnapConstant from '../../../utils/OnapConstants'; +import { shallow } from 'enzyme'; describe('Verify PolicyModal', () => { beforeEach(() => { @@ -52,6 +53,7 @@ describe('Verify PolicyModal', () => { "jsonRepresentation": { "schema": {} } }] }; + const loopCache = new LoopCache(loopCacheStr); const historyMock = { push: jest.fn() }; const flushPromises = () => new Promise(setImmediate); @@ -125,4 +127,9 @@ describe('Verify PolicyModal', () => { instance.handlePdpSubgroupChange(event); expect(component.state('chosenPdpSubgroup')).toEqual("option1"); }); + + it('Test the render method', () => { + const component = shallow() + expect(component).toMatchSnapshot(); + }); }); diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js new file mode 100644 index 0000000..8093b7e --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ + +import React from 'react' +import Modal from 'react-bootstrap/Modal'; +import Form from 'react-bootstrap/Form'; +import Row from 'react-bootstrap/Row'; +import Col from 'react-bootstrap/Col'; +import styled from 'styled-components'; +import Alert from 'react-bootstrap/Alert'; +import { Input, InputLabel, Button, SvgIcon } from "@material-ui/core"; +import PublishIcon from '@material-ui/icons/Publish'; +import PolicyService from '../../../api/PolicyService'; + +const ModalStyled = styled(Modal)` + background-color: transparent; +` + +const StyledMessagesDiv = styled.div` + overflow: auto; + max-height: 300px; +` + + +export default class PolicyToscaFileSelector extends React.Component { + + state = { + show: this.props.show, + alertMessages: [], + } + + constructor(props, context) { + super(props, context); + this.handleClose = this.handleClose.bind(this); + this.onFileChange = this.onFileChange.bind(this); + } + + componentDidUpdate(prevProps) { + if (this.props.show !== this.state.show) { + this.setState({ show: this.props.show }); + } + } + + handleClose() { + this.props.disableFunction(); + this.setState({ alertMessages: [] }); + } + + onFileChange(target) { + this.setState({ alertMessages: [] }); + target.currentTarget.files.forEach(file => { + const fileReader = new FileReader(); + fileReader.readAsDataURL(file); + fileReader.onload = (content) => { + PolicyService.sendNewPolicyModel(atob(content.target.result.split(",")[1])).then(respModelCreate => { + if (typeof (respModelCreate) === "undefined") { + //it indicates a failure + this.setState(state => { + return { + alertMessages: [...state.alertMessages, ({ file.name }

Policy Tosca Model Creation Failure

+
+

Type: { file.type }

Size: { file.size }

)] + }; + }); + } else { + this.props.toscaTableUpdateFunction(); + this.setState(state => { + return { + alertMessages: [...state.alertMessages, ({ file.name }

Policy Tosca Model Created Successfully

+
+

Type: { file.type }

Size: { file.size }

)] + }; + }); + } + }); + }; + }); + + } + + render() { + return ( + + + Create New Policy Tosca Model + + + + + + + + { this.state.alertMessages } + + + + + + + + + ); + } +} diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js index ce4edce..fc69a63 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js @@ -26,8 +26,7 @@ import PolicyToscaService from '../../../api/PolicyToscaService'; import styled from 'styled-components'; import Button from 'react-bootstrap/Button'; -const JsonEditorDiv = styled.div` - margin-top: 20px; +const ToscaDiv = styled.div` background-color: ${ props => props.theme.toscaTextareaBackgroundColor }; text-align: justify; font-size: ${ props => props.theme.toscaTextareaFontSize }; @@ -57,11 +56,11 @@ export default class ToscaViewer extends React.Component { render() { return ( - +
{ this.state.yamlPolicyTosca }
-
+ ); } } diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js new file mode 100644 index 0000000..5b59760 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2021 AT&T Intellectual Property. All rights + * reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END============================================ + * =================================================================== + * + */ +import React from 'react'; +import ToscaViewer from './ToscaViewer'; +import { shallow, mount } from 'enzyme'; +import PolicyToscaService from '../../../api/PolicyToscaService'; + +describe('Verify ToscaViewer', () => { + const fs = require('fs'); + + let toscaYaml = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.yaml', { encoding: 'utf8', flag: 'r' }) + + const toscaData = { + "policyModelType": "onap.policies.controlloop.Guard", + "version": "1.0.0", + "policyAcronym": "Guard", + "createdDate": "2021-04-09T02:29:31.407356Z", + "updatedDate": "2021-04-09T02:29:31.407356Z", + "updatedBy": "Not found", + "createdBy": "Not found", + "tableData": { + "id": 0 + } + }; + + it('Test the render method', async () => { + PolicyToscaService.getToscaPolicyModelYaml = jest.fn().mockImplementation(() => { + return Promise.resolve(toscaYaml); + }); + const component = shallow(); + await PolicyToscaService.getToscaPolicyModelYaml(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js index a97deea..f571bc1 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js @@ -43,24 +43,27 @@ import ViewColumn from '@material-ui/icons/ViewColumn'; import DehazeIcon from '@material-ui/icons/Dehaze'; import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos'; import AddIcon from '@material-ui/icons/Add'; -import FormControlLabel from '@material-ui/core/FormControlLabel'; +import PublishIcon from '@material-ui/icons/Publish'; import Switch from '@material-ui/core/Switch'; import MaterialTable from "material-table"; import PolicyService from '../../../api/PolicyService'; import PolicyToscaService from '../../../api/PolicyToscaService'; -import Select from 'react-select'; +import Select from '@material-ui/core/Select'; import Alert from 'react-bootstrap/Alert'; import Tabs from 'react-bootstrap/Tabs'; import Tab from 'react-bootstrap/Tab'; import PolicyEditor from './PolicyEditor'; import ToscaViewer from './ToscaViewer'; +import PolicyDeploymentEditor from './PolicyDeploymentEditor'; +import PoliciesTreeViewer from './PoliciesTreeViewer'; +import PolicyToscaFileSelector from './PolicyToscaFileSelector'; const DivWhiteSpaceStyled = styled.div` white-space: pre; ` const ModalStyled = styled(Modal)` - @media (min-width: 1000px) { + @media (min-width: 800px) { .modal-xl { max-width: 96%; } @@ -73,26 +76,38 @@ const DetailedRow = styled.div` font-size: ${ props => props.theme.policyEditorFontSize }; width: 97%; margin-left: auto; - margin-right: 0; + margin-right: auto; + margin-top: 20px; ` +const PoliciesTreeViewerDiv = styled.div` + width: 20%; + float: left; + left: 0; + overflow: auto; +` + +const MaterialTableDiv = styled.div` + float: right; + width: 80%; + left: 20%; +` const standardCellStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' }; -const cellPdpGroupStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' }; const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' }; const rowHeaderStyle = { backgroundColor: '#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black' }; export default class ViewAllPolicies extends React.Component { state = { show: true, - content: 'Please select a policy to display it', - selectedRowId: -1, policiesListData: [], + policiesListDataFiltered: [], toscaModelsListData: [], + toscaModelsListDataFiltered: [], jsonEditorForPolicy: new Map(), - prefixGrouping: false, showSuccessAlert: false, showFailAlert: false, + showFileSelector: false, policyColumnsDefinition: [ { title: "Policy Name", field: "name", @@ -102,7 +117,7 @@ export default class ViewAllPolicies extends React.Component { { title: "Policy Version", field: "version", cellStyle: standardCellStyle, - headerStyle: headerStyle + headerStyle: headerStyle, }, { title: "Policy Type", field: "type", @@ -115,20 +130,13 @@ export default class ViewAllPolicies extends React.Component { headerStyle: headerStyle }, { - title: "Deployed in PDP", field: "pdpGroupInfo.pdpGroup", - cellStyle: cellPdpGroupStyle, - headerStyle: headerStyle, - render: rowData => this.renderPdpGroupDropBox(rowData), - grouping: false - }, - { - title: "PDP Group", field: "pdpGroupInfo.pdpGroup", - cellStyle: cellPdpGroupStyle, + title: "Deployable in PDP Group", field: "supportedPdpGroupsString", + cellStyle: standardCellStyle, headerStyle: headerStyle }, { - title: "PDP SubGroup", field: "pdpGroupInfo.pdpSubGroup", - cellStyle: cellPdpGroupStyle, + title: "Deployed in PDP Group", field: "pdpGroupInfoString", + cellStyle: standardCellStyle, headerStyle: headerStyle } ], @@ -183,62 +191,63 @@ export default class ViewAllPolicies extends React.Component { constructor(props, context) { super(props, context); this.handleClose = this.handleClose.bind(this); - this.renderPdpGroupDropBox = this.renderPdpGroupDropBox.bind(this); - this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this); - this.handlePrefixGrouping = this.handlePrefixGrouping.bind(this); this.handleDeletePolicy = this.handleDeletePolicy.bind(this); this.disableAlert = this.disableAlert.bind(this); this.getAllPolicies = this.getAllPolicies.bind(this); this.getAllToscaModels = this.getAllToscaModels.bind(this); + this.generateAdditionalPolicyColumns = this.generateAdditionalPolicyColumns.bind(this); + this.filterPolicies = this.filterPolicies.bind(this); + this.filterTosca = this.filterTosca.bind(this); + this.showFileSelector = this.showFileSelector.bind(this); + this.disableFileSelector = this.disableFileSelector.bind(this); this.getAllPolicies(); this.getAllToscaModels(); } - getAllToscaModels() { - PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => { - this.setState({ toscaModelsListData: toscaModelsList }); - }); - } - - handlePdpGroupChange(e) { - let pdpSplit = e.value.split("/"); - let selectedPdpGroup = pdpSplit[0]; - let selectedSubPdpGroup = pdpSplit[1]; - if (typeof selectedSubPdpGroup !== "undefined") { - let temp = this.state.policiesListData; - temp[this.state.selectedRowId]["pdpGroupInfo"] = { "pdpGroup": selectedPdpGroup, "pdpSubGroup": selectedSubPdpGroup }; - this.setState({ policiesListData: temp }); - } else { - delete this.state.policiesListData[this.state.selectedRowId]["pdpGroupInfo"]; - } - } + generateAdditionalPolicyColumns(policiesData) { + policiesData.forEach(policy => { + let supportedPdpGroupsString = ""; + if (typeof policy.supportedPdpGroups !== "undefined") { + for (const pdpGroup of policy["supportedPdpGroups"]) { + for (const pdpSubGroup of Object.values(pdpGroup)[0]) { + supportedPdpGroupsString += (Object.keys(pdpGroup)[0] + "/" + pdpSubGroup + "\r\n"); + } + } + policy["supportedPdpGroupsString"] = supportedPdpGroupsString; + } - renderPdpGroupDropBox(dataRow) { - let optionItems = [{ label: "NOT DEPLOYED", value: "NOT DEPLOYED" }]; - let selectedItem = { label: "NOT DEPLOYED", value: "NOT DEPLOYED" }; - if (typeof dataRow.supportedPdpGroups !== "undefined") { - for (const pdpGroup of dataRow["supportedPdpGroups"]) { - for (const pdpSubGroup of Object.values(pdpGroup)[0]) { - optionItems.push({ - label: Object.keys(pdpGroup)[0] + "/" + pdpSubGroup, - value: Object.keys(pdpGroup)[0] + "/" + pdpSubGroup + let infoPdpGroup = ""; + if (typeof policy.pdpGroupInfo !== "undefined") { + policy["pdpGroupInfo"].forEach(pdpGroupElem => { + let groupName = Object.keys(pdpGroupElem)[0]; + pdpGroupElem[groupName]["pdpSubgroups"].forEach(pdpSubGroupElem => { + infoPdpGroup += (groupName + "/" + pdpSubGroupElem["pdpType"] + " (" + + pdpGroupElem[groupName]["pdpGroupState"] + ")" + "\r\n"); }); - } + policy["pdpGroupInfoString"] = infoPdpGroup; + }); } - } - if (typeof dataRow.pdpGroupInfo !== "undefined") { - selectedItem = { - label: dataRow["pdpGroupInfo"]["pdpGroup"] + "/" + dataRow["pdpGroupInfo"]["pdpSubGroup"], - value: dataRow["pdpGroupInfo"]["pdpGroup"] + "/" + dataRow["pdpGroupInfo"]["pdpSubGroup"] - }; - } - return (
+ + Required +  * + + } + labelWidth={0} + notched={true} + > + + Required +  * + + } + labelWidth={0} + notched={true} + > +
+ + + Required +  * + + +
+
+
+
+ + + + + + + + + + + + + +
+ + + + + + + + + + + Required +  * + + } + multiline={false} + onChange={[Function]} + > + + Required +  * + + } + multiline={false} + onChange={[Function]} + > + + +
+ + + Required +  * + + } + labelWidth={0} + notched={true} + > + + Required +  * + + } + labelWidth={0} + notched={true} + > +
+ + + Required +  * + + +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + +
+ +
+
+
+`; diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap new file mode 100644 index 0000000..8b1261b --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap @@ -0,0 +1,159 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Verify PolicyModal Test the render method 1`] = ` + + + + Edit the policy + + + + + + + + + +
+ + + Pdp Group Info + + + + + + + + + + + + + + + +`; diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap new file mode 100644 index 0000000..61fb485 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap @@ -0,0 +1,30 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Verify ToscaViewer Test the render method 1`] = ` + +
+    tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+  onap.policies.controlloop.Guard:
+    properties: {
+    }
+    name: onap.policies.controlloop.Guard
+    version: 1.0.0
+    derived_from: tosca.policies.Root
+    metadata: {
+    }
+    description: Guard Policies for Control Loop Operational Policies
+name: ToscaServiceTemplateSimple
+version: 1.0.0
+
+  
+ +
+`; diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json new file mode 100644 index 0000000..3b001b3 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json @@ -0,0 +1,179 @@ +{ + "title": "onap.policies.monitoring.tcagen2", + "type": "object", + "required": [ + "tca.policy" + ], + "properties": { + "tca.policy": { + "title": "onap.datatypes.monitoring.tca_policy", + "type": "object", + "required": [ + "domain", + "metricsPerEventName" + ], + "properties": { + "domain": { + "type": "string", + "description": "Domain name to which TCA needs to be applied", + "default": "measurementsForVfScaling", + "const": "measurementsForVfScaling" + }, + "metricsPerEventName": { + "type": "array", + "description": "Contains eventName and threshold details that need to be applied to given eventName", + "items": { + "title": "onap.datatypes.monitoring.metricsPerEventName", + "type": "object", + "required": [ + "controlLoopSchemaType", + "eventName", + "policyName", + "policyScope", + "policyVersion", + "thresholds" + ], + "properties": { + "controlLoopSchemaType": { + "type": "string", + "description": "Specifies Control Loop Schema Type for the event Name e.g. VNF, VM", + "enum": [ + "VM", + "VNF" + ] + }, + "eventName": { + "type": "string", + "description": "Event name to which thresholds need to be applied" + }, + "policyName": { + "type": "string", + "description": "TCA Policy Scope Name" + }, + "policyScope": { + "type": "string", + "description": "TCA Policy Scope" + }, + "policyVersion": { + "type": "string", + "description": "TCA Policy Scope Version" + }, + "thresholds": { + "type": "array", + "description": "Thresholds associated with eventName", + "items": { + "title": "onap.datatypes.monitoring.thresholds", + "type": "object", + "required": [ + "closedLoopControlName", + "closedLoopEventStatus", + "direction", + "fieldPath", + "severity", + "thresholdValue", + "version" + ], + "properties": { + "closedLoopControlName": { + "type": "string", + "description": "Closed Loop Control Name associated with the threshold" + }, + "closedLoopEventStatus": { + "type": "string", + "description": "Closed Loop Event Status of the threshold", + "enum": [ + "ONSET", + "ABATED" + ] + }, + "direction": { + "type": "string", + "description": "Direction of the threshold", + "enum": [ + "LESS", + "LESS_OR_EQUAL", + "GREATER", + "GREATER_OR_EQUAL", + "EQUAL" + ] + }, + "fieldPath": { + "type": "string", + "description": "Json field Path as per CEF message which needs to be analyzed for TCA", + "enum": [ + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated", + "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait", + "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage", + "$.event.measurementsForVfScalingFields.meanRequestLatency", + "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered", + "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached", + "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured", + "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree", + "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed", + "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value" + ] + }, + "severity": { + "type": "string", + "description": "Threshold Event Severity", + "enum": [ + "CRITICAL", + "MAJOR", + "MINOR", + "WARNING", + "NORMAL" + ] + }, + "thresholdValue": { + "type": "integer", + "description": "Threshold value for the field Path inside CEF message" + }, + "version": { + "type": "string", + "description": "Version number associated with the threshold" + } + } + }, + "format": "tabs-top" + } + } + }, + "format": "tabs-top" + } + } + } + } +} diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml new file mode 100644 index 0000000..15a3cec --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml @@ -0,0 +1,13 @@ +tosca_definitions_version: tosca_simple_yaml_1_1_0 +policy_types: + onap.policies.controlloop.Guard: + properties: { + } + name: onap.policies.controlloop.Guard + version: 1.0.0 + derived_from: tosca.policies.Root + metadata: { + } + description: Guard Policies for Control Loop Operational Policies +name: ToscaServiceTemplateSimple +version: 1.0.0 diff --git a/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js b/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js index 7257337..e7be984 100644 --- a/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js @@ -1,8 +1,8 @@ /*- * ============LICENSE_START======================================================= - * ONAP CLAMP + * ONAP POLICY-CLAMP * ================================================================================ - * Copyright (C) 2019 AT&T Intellectual Property. All rights + * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights * reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js b/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js index e58c61a..d452f6d 100644 --- a/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js @@ -60,7 +60,7 @@ export default class UserInfoModal extends React.Component { renderPermissions() { if (this.state.userInfo["allPermissions"]) { var listOfPermissions = this.state.userInfo["allPermissions"].map(function (perm) { - return ; + return ; }) return listOfPermissions; } else { diff --git a/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap index 7c725bc..548a2d9 100644 --- a/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap +++ b/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap @@ -91,11 +91,13 @@ exports[`Verify UserInfoModal Test the render method full permission 1`] = ` diff --git a/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js b/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js index b03b740..3435ba3 100644 --- a/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js +++ b/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js @@ -67,10 +67,9 @@ export default class LoopLogs extends React.Component { } renderLogs() { - if (this.state.loopCache.getLoopLogsArray() != null) { - return ( - this.state.loopCache.getLoopLogsArray().map(row => ) - ) + let logsArray = this.state.loopCache.getLoopLogsArray(); + if (logsArray != null) { + return (logsArray.map(row => )); } } diff --git a/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap b/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap index 75b817b..996c674 100644 --- a/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap +++ b/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap @@ -45,6 +45,7 @@ exports[`Verify LoopLogs Test the render method 1`] = ` { + let componentStates = this.state.loopCache.getComponentStates(); + if (componentStates != null) { + return Object.keys(componentStates).map((key) => { console.debug("Adding status for: ", key); var res = {} res[key] = this.state.loopCache.getComponentStates()[key]; - return ( No LOOP (SVG) ); +const emptySvg = ( + No LOOP (SVG) +); class SvgGenerator extends React.Component { - boxWidth = 200; - boxHeight = 100; - boxSpace = 50; - - static GENERATED_FROM_INSTANCE = "INSTANCE"; - static GENERATED_FROM_TEMPLATE = "TEMPLATE"; - - state = { - loopCache: new LoopCache({}), - clickable: false, - generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE - } - - constructor(props) { - super(props); - this.state.loopCache = props.loopCache; - this.state.clickable = props.clickable; - this.state.generatedFrom = props.generatedFrom; - this.handleSvgClick = this.handleSvgClick.bind(this); - this.renderSvg = this.renderSvg.bind(this); - } - - shouldComponentUpdate(nextProps, nextState) { - return this.state.loopCache !== nextState.loopCache; - } - - componentWillReceiveProps(newProps) { - if (this.state.loopCache !== newProps.loopCache) { - this.setState({ - loopCache: newProps.loopCache, - }); - } - } - - handleSvgClick(event) { - console.debug("svg click event received"); - if (this.state.clickable) { - var elementName = event.target.parentNode.getAttribute('policyId'); - console.info("SVG element clicked", elementName); - // Only allow movement to policy editing IF there busyLoadingCOunt is 0, - // meaning we are not waiting for refreshStatus to complete, for example - if (elementName !== null && !this.props.isBusyLoading()) { - this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName); - } - } - } - - createVesBox (xPos) { - return this.createOneBox(xPos,null,null,'VES Collector','VES',null); + boxWidth = 200; + boxHeight = 100; + boxSpace = 50; + + static GENERATED_FROM_INSTANCE = "INSTANCE"; + static GENERATED_FROM_TEMPLATE = "TEMPLATE"; + + state = { + loopCache: new LoopCache({}), + clickable: false, + generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE + } + + constructor(props) { + super(props); + this.state.loopCache = props.loopCache; + this.state.clickable = props.clickable; + this.state.generatedFrom = props.generatedFrom; + this.handleSvgClick = this.handleSvgClick.bind(this); + this.renderSvg = this.renderSvg.bind(this); + } + + shouldComponentUpdate(nextProps, nextState) { + return this.state.loopCache !== nextProps.loopCache; + } + + componentDidUpdate(prevProps) { + if (prevProps.loopCache !== this.props.loopCache) { + this.setState({ + loopCache: this.props.loopCache, + }); } - - createOneArrow(xPos) { - return ( - - - - - - - - - ); - } - - createBeginCircle(xPos, text) { - return ( - - - {text} - - ); + } + + handleSvgClick(event) { + console.debug("svg click event received"); + if (this.state.clickable) { + var elementName = event.target.parentNode.getAttribute('policyId'); + console.info("SVG element clicked", elementName); + // Only allow movement to policy editing IF there busyLoadingCOunt is 0, + // meaning we are not waiting for refreshStatus to complete, for example + if (elementName !== null && !this.props.isBusyLoading()) { + this.props.history.push("/policyModal/" + event.target.parentNode.getAttribute('policyType') + "/" + elementName); + } } - - createEndCircle(xPos, text) { - return ( - - - {text} - - ); + } + + createVesBox(xPos) { + return this.createOneBox(xPos, null, null, 'VES Collector', 'VES', null); + } + + createOneArrow(xPos) { + return ( + + + + + + + + + ); + } + + createBeginCircle(xPos, text) { + return ( + + + { text } + + ); + } + + createEndCircle(xPos, text) { + return ( + + + { text } + + ); + } + + createOneBox(xPos, policyId, loopElementModelId, name, title, policyType) { + return ( + + + + { title } + { name } + { policyId } + + + ); + } + + createSvgFromTemplate() { + const allElements = []; + var xPos = 0; + + allElements.push(this.createBeginCircle(xPos, "Start")) + xPos += (this.boxWidth + this.boxSpace); + + allElements.push(this.createOneArrow(xPos - this.boxSpace)); + + allElements.push(this.createVesBox(xPos)); + xPos += (this.boxWidth + this.boxSpace); + + allElements.push(this.createOneArrow(xPos - this.boxSpace)); + //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) + for (var loopElement of this.state.loopCache.getAllLoopElementModels()) { + + allElements.push(this.createOneBox(xPos, + loopElement['name'], + loopElement['name'], + loopElement['shortName'], + loopElement['loopElementType'], + loopElement['loopElementType'])) + xPos += (this.boxWidth + this.boxSpace); + allElements.push(this.createOneArrow(xPos - this.boxSpace)); } - createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) { - return ( - - - - {title} - {name} - {policyId} - - - ); - } + allElements.push(this.createEndCircle(xPos, "End")) + xPos += (this.boxWidth + this.boxSpace); - createSvgFromTemplate() { - const allElements = []; - var xPos = 0; + return allElements; + } - allElements.push(this.createBeginCircle(xPos,"Start")) - xPos+=(this.boxWidth+this.boxSpace); + createSvgFromInstance() { + const allElements = []; + var xPos = 0; - allElements.push(this.createOneArrow(xPos-this.boxSpace)); + allElements.push(this.createBeginCircle(xPos, "Start")) + xPos += (this.boxWidth + this.boxSpace); - allElements.push(this.createVesBox(xPos)); - xPos+=(this.boxWidth+this.boxSpace); + allElements.push(this.createOneArrow(xPos - this.boxSpace)); - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) - for (var loopElement of this.state.loopCache.getAllLoopElementModels()) { + allElements.push(this.createVesBox(xPos)); + xPos += (this.boxWidth + this.boxSpace); - allElements.push(this.createOneBox(xPos, - loopElement['name'], - loopElement['name'], - loopElement['shortName'], - loopElement['loopElementType'], - loopElement['loopElementType'])) - xPos+=(this.boxWidth+this.boxSpace); - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - } + allElements.push(this.createOneArrow(xPos - this.boxSpace)); - allElements.push(this.createEndCircle(xPos, "End")) - xPos+=(this.boxWidth+this.boxSpace); - - return allElements; + for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) { + var loopElementModelName = this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel']; + if (loopElementModelName !== undefined) { + loopElementModelName = loopElementModelName['name']; + } + allElements.push(this.createOneBox(xPos, + this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'], + loopElementModelName, + this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'], + 'microservice', + OnapConstant.microServiceType)) + xPos += (this.boxWidth + this.boxSpace); + allElements.push(this.createOneArrow(xPos - this.boxSpace)); } - createSvgFromInstance() { - const allElements = []; - var xPos = 0; - - allElements.push(this.createBeginCircle(xPos,"Start")) - xPos+=(this.boxWidth+this.boxSpace); - - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - - allElements.push(this.createVesBox(xPos)); - xPos+=(this.boxWidth+this.boxSpace); - - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - - for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) { - var loopElementModelName = this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel']; - if (loopElementModelName !== undefined) { - loopElementModelName = loopElementModelName['name']; - } - allElements.push(this.createOneBox(xPos, - this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'], - loopElementModelName, - this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'], - 'microservice', - OnapConstant.microServiceType)) - xPos+=(this.boxWidth+this.boxSpace); - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - } - - for (var opPolicy in this.state.loopCache.getOperationalPolicies()) { - loopElementModelName = this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel']; - if (loopElementModelName !== undefined) { - loopElementModelName = loopElementModelName['name']; - } - allElements.push(this.createOneBox(xPos, - this.state.loopCache.getOperationalPolicies()[opPolicy]['name'], - loopElementModelName, - this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'], - 'operational', - OnapConstant.operationalPolicyType)) - xPos+=(this.boxWidth+this.boxSpace); - allElements.push(this.createOneArrow(xPos-this.boxSpace)); - } - - allElements.push(this.createEndCircle(xPos, "End")) - xPos+=(this.boxWidth+this.boxSpace); - - return allElements; + for (var opPolicy in this.state.loopCache.getOperationalPolicies()) { + loopElementModelName = this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel']; + if (loopElementModelName !== undefined) { + loopElementModelName = loopElementModelName['name']; + } + allElements.push(this.createOneBox(xPos, + this.state.loopCache.getOperationalPolicies()[opPolicy]['name'], + loopElementModelName, + this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'], + 'operational', + OnapConstant.operationalPolicyType)) + xPos += (this.boxWidth + this.boxSpace); + allElements.push(this.createOneArrow(xPos - this.boxSpace)); } - renderSvg() { - if (this.state.loopCache.getLoopName() === undefined) { - return [emptySvg]; - } - if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) { - return this.createSvgFromInstance(); - } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) { - return this.createSvgFromTemplate(); - } - } + allElements.push(this.createEndCircle(xPos, "End")) + xPos += (this.boxWidth + this.boxSpace); + + return allElements; + } - render() { - var allTheElements = this.renderSvg(); - var svgWidth = this.boxWidth*allTheElements.length; - var svgHeight = this.boxHeight+50; - return ( - - - - - {allTheElements} - - - - ); + renderSvg() { + if (this.state.loopCache.getLoopName() === undefined) { + return [emptySvg]; } + if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) { + return this.createSvgFromInstance(); + } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) { + return this.createSvgFromTemplate(); + } + } + + render() { + var allTheElements = this.renderSvg(); + var svgWidth = this.boxWidth * allTheElements.length; + var svgHeight = this.boxHeight + 50; + return ( + + + + + { allTheElements } + + + + ); + } } export default withRouter(SvgGenerator); diff --git a/gui-clamp/ui-react/src/setupTests.js b/gui-clamp/ui-react/src/setupTests.js index f553583..30ce019 100644 --- a/gui-clamp/ui-react/src/setupTests.js +++ b/gui-clamp/ui-react/src/setupTests.js @@ -22,7 +22,7 @@ */ import { configure } from 'enzyme'; -import Adapter from 'enzyme-adapter-react-17-updated'; +import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; configure({ adapter: new Adapter() }); -global.fetch = require('jest-fetch-mock'); \ No newline at end of file +global.fetch = require('jest-fetch-mock'); -- cgit 1.2.3-korg