diff options
Diffstat (limited to 'runtime/ui-react/src/components/dialogs/Policy')
15 files changed, 2918 insertions, 0 deletions
diff --git a/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js b/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js new file mode 100644 index 000000000..9c2f102b4 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js @@ -0,0 +1,109 @@ +/*- + * ============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 TreeView from '@material-ui/lab/TreeView'; +import TreeItem from '@material-ui/lab/TreeItem'; +import FolderIcon from '@material-ui/icons/Folder'; +import FolderOpenIcon from '@material-ui/icons/FolderOpen'; +import DescriptionIcon from '@material-ui/icons/Description'; + + +export default class PoliciesTreeViewer extends React.Component { + + separator = "."; + + nodesList = new Map(); + + constructor(props, context) { + super(props, context); + this.createPoliciesTree = this.createPoliciesTree.bind(this); + this.handleTreeItemClick = this.handleTreeItemClick.bind(this); + this.buildNameWithParent = this.buildNameWithParent.bind(this); + + } + + state = { + policiesTreeData: this.createPoliciesTree(this.props.policiesData), + } + + componentDidUpdate(prevProps) { + if (prevProps.policiesData !== this.props.policiesData) { + this.setState({policiesTreeData: this.createPoliciesTree(this.props.policiesData)}) + } + } + + createPoliciesTree(policiesArray) { + // put my policies array in a Json + let nodeId = 1; + let root = {id:nodeId, policyCount:0, name:"ROOT", children:[], parent: undefined}; + this.nodesList.set(nodeId++, root); + + policiesArray.forEach(policy => { + 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 (<TreeItem key={nodes.id} nodeId={nodes.id} label={nodes.name + "("+ nodes.policyCount + ")"} onNodeSelect={this.handleTreeItemClick}> + { + Array.isArray(nodes.children) ? nodes.children.map((node) => this.renderTreeItems(node)) : null + } + </TreeItem>); + }; + + render() { + return ( + <TreeView defaultExpanded={['root']} defaultCollapseIcon={<FolderOpenIcon />} + defaultExpandIcon={<FolderIcon />} defaultEndIcon={<DescriptionIcon />} onNodeSelect={this.handleTreeItemClick} multiSelect> + {this.renderTreeItems(this.state.policiesTreeData)} + </TreeView> + ); + } +}
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js new file mode 100644 index 000000000..57d61600a --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js @@ -0,0 +1,176 @@ +/*- + * ============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 <FormControlLabel control={<Checkbox checked={item.value} onChange={this.handleCheckboxChange} + name={item.name} />} label={item.name} />; + }); + } + + render() { + return ( + <PanelDiv> + <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Button variant="secondary" title="Update the policy to the specified PDP Groups/Subgroups" + onClick={this.handleUpdatePdpDeployment}>Update PDP</Button> + <FormGroup>{this.renderPdpDeploymentCheckboxes()}</FormGroup> + </PanelDiv> + ); + } + }
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js new file mode 100644 index 000000000..be77f14e9 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.js @@ -0,0 +1,192 @@ +/*- + * ============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 PolicyToscaService from '../../../api/PolicyToscaService'; +import { JSONEditor } from '@json-editor/json-editor/dist/nonmin/jsoneditor.js'; +import "@fortawesome/fontawesome-free/css/all.css" +import styled from 'styled-components'; +import Button from 'react-bootstrap/Button'; +import TextField from '@material-ui/core/TextField'; +import Alert from 'react-bootstrap/Alert'; +import PolicyService from '../../../api/PolicyService'; +import OnapUtils from '../../../utils/OnapUtils'; + +const DivWhiteSpaceStyled = styled.div` + white-space: pre; +` + +const JsonEditorDiv = styled.div` + margin-top: 20px; + background-color: ${props => props.theme.loopViewerBackgroundColor}; + text-align: justify; + font-size: ${props => props.theme.policyEditorFontSize}; + border: 1px solid #C0C0C0; +` +const PanelDiv = styled.div` + text-align: justify; + font-size: ${props => props.theme.policyEditorFontSize}; + background-color: ${props => props.theme.loopViewerBackgroundColor}; +` + +export default class PolicyEditor extends React.Component { + + state = { + policyModelType: this.props.policyModelType, + policyModelTypeVersion: this.props.policyModelTypeVersion, + policyName: (typeof this.props.policyName !== "undefined") ? this.props.policyName : "org.onap.policy.new", + policyVersion: (typeof this.props.policyVersion !== "undefined") ? this.props.policyVersion : "0.0.1", + policyProperties: this.props.policyProperties, + showSuccessAlert: false, + showFailAlert: false, + jsonEditor: null, + jsonEditorDivId: this.props.policyModelType + "_" + this.props.policyModelTypeVersion + "_" + this.props.policyName + "_" + this.props.policyVersion, + } + + constructor(props, context) { + super(props, context); + this.createJsonEditor = this.createJsonEditor.bind(this); + this.getToscaModelForPolicy = this.getToscaModelForPolicy.bind(this); + this.disableAlert = this.disableAlert.bind(this); + this.handleCreateNewVersion = this.handleCreateNewVersion.bind(this); + this.handleChangePolicyName = this.handleChangePolicyName.bind(this); + this.handleChangePolicyVersion = this.handleChangePolicyVersion.bind(this); + } + + disableAlert() { + this.setState ({ showSuccessAlert: false, showFailAlert: false }); + } + + customValidation(editorData) { + // method for sub-classes to override with customized validation + return []; + } + + handleCreateNewVersion() { + var editorData = this.state.jsonEditor.getValue(); + var errors = this.state.jsonEditor.validate(); + errors = errors.concat(this.customValidation(editorData)); + + if (errors.length !== 0) { + console.error("Errors detected during policy data validation ", errors); + this.setState({ + showFailAlert: true, + showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors) + }); + return; + } else { + console.info("NO validation errors found in policy data"); + PolicyService.createNewPolicy(this.state.policyModelType, this.state.policyModelTypeVersion, + this.state.policyName, this.state.policyVersion, editorData).then(respPolicyCreation => { + if (typeof(respPolicyCreation) === "undefined") { + //it indicates a failure + this.setState({ + showFailAlert: true, + showMessage: 'Policy Creation Failure' + }); + } else { + this.setState({ + showSuccessAlert: true, + showMessage: 'Policy '+ this.state.policyName + '/' + this.state.policyVersion + ' created successfully' + }); + this.props.policiesTableUpdateFunction(); + } + }) + } + } + + getToscaModelForPolicy() { + PolicyToscaService.getToscaPolicyModel(this.state.policyModelType, this.state.policyModelTypeVersion).then(respJsonPolicyTosca => { + if (respJsonPolicyTosca !== {}) { + this.setState({ + jsonSchemaPolicyTosca: respJsonPolicyTosca, + jsonEditor: this.createJsonEditor(respJsonPolicyTosca, this.state.policyProperties), + }) + } + }); + } + + componentDidMount() { + this.getToscaModelForPolicy(); + } + + createJsonEditor(toscaModel, editorData) { + return new JSONEditor(document.getElementById(this.state.jsonEditorDivId), + { + schema: toscaModel, + startval: editorData, + theme: 'bootstrap4', + iconlib: 'fontawesome5', + object_layout: 'grid', + disable_properties: false, + disable_edit_json: false, + disable_array_reorder: true, + disable_array_delete_last_row: true, + disable_array_delete_all_rows: false, + array_controls_top: true, + keep_oneof_values: false, + collapsed: true, + show_errors: 'always', + display_required_only: false, + show_opt_in: false, + prompt_before_delete: true, + required_by_default: false + }) + } + + handleChangePolicyName(event) { + this.setState({ + policyName: event.target.value, + }); + } + + handleChangePolicyVersion(event) { + this.setState({ + policyVersion: event.target.value, + }); + } + + render() { + return ( + <PanelDiv> + <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <TextField required id="policyName" label="Required" defaultValue={this.state.policyName} + onChange={this.handleChangePolicyName} variant="outlined" size="small"/> + <TextField required id="policyVersion" label="Required" defaultValue={this.state.policyVersion} + onChange={this.handleChangePolicyVersion} size="small" variant="outlined"/> + <Button variant="secondary" title="Create a new policy version from the defined parameters" + onClick={this.handleCreateNewVersion}>Create New Version</Button> + <JsonEditorDiv id={this.state.jsonEditorDivId} title="Policy Properties"/> + </PanelDiv> + ); + } +}
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js new file mode 100644 index 000000000..0b734430a --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js @@ -0,0 +1,71 @@ +/*- + * ============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(<PolicyEditor policyModelType="onap.policies.monitoring.tcagen2" policyModelTypeVersion="1.0.0" + policyName="org.onap.new" policyVersion="1.0.0" policyProperties={policyProperties} + policiesTableUpdateFunction={() => {}} />); + await PolicyToscaService.getToscaPolicyModel(); + expect(component).toMatchSnapshot(); + }); +});
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js new file mode 100644 index 000000000..4a883fffa --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.js @@ -0,0 +1,345 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2020-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 Button from 'react-bootstrap/Button'; +import Form from 'react-bootstrap/Form'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import Select from 'react-select'; +import Modal from 'react-bootstrap/Modal'; +import styled from 'styled-components'; +import LoopService from '../../../api/LoopService'; +import LoopCache from '../../../api/LoopCache'; +import { JSONEditor } from '@json-editor/json-editor/dist/jsoneditor.js'; +import "@fortawesome/fontawesome-free/css/all.css" +import Alert from 'react-bootstrap/Alert'; +import OnapConstant from '../../../utils/OnapConstants'; +import OnapUtils from '../../../utils/OnapUtils'; + +const ModalStyled = styled(Modal)` + background-color: transparent; +` + +const DivWhiteSpaceStyled = styled.div` + white-space: pre; +` + +export default class PolicyModal extends React.Component { + + state = { + show: true, + loopCache: this.props.loopCache, + jsonEditor: null, + policyName: this.props.match.params.policyName, + // This is to indicate whether it's an operational or config policy (in terms of loop instance) + policyInstanceType: this.props.match.params.policyInstanceType, + pdpGroup: null, + pdpGroupList: [], + pdpSubgroupList: [], + chosenPdpGroup: '', + chosenPdpSubgroup: '', + showSucAlert: false, + showFailAlert: false + }; + + constructor(props, context) { + super(props, context); + this.handleClose = this.handleClose.bind(this); + this.handleSave = this.handleSave.bind(this); + this.renderJsonEditor = this.renderJsonEditor.bind(this); + this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this); + this.handlePdpSubgroupChange = this.handlePdpSubgroupChange.bind(this); + this.createJsonEditor = this.createJsonEditor.bind(this); + this.handleRefresh = this.handleRefresh.bind(this); + this.disableAlert = this.disableAlert.bind(this); + this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this); + this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this); + this.renderModalTitle = this.renderModalTitle.bind(this); + this.readOnly = props.readOnly !== undefined ? props.readOnly : false; + } + + handleSave() { + var editorData = this.state.jsonEditor.getValue(); + var errors = this.state.jsonEditor.validate(); + errors = errors.concat(this.customValidation(editorData, this.state.loopCache.getTemplateName())); + + if (errors.length !== 0) { + console.error("Errors detected during policy data validation ", errors); + this.setState({ + showFailAlert: true, + showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors) + }); + return; + } + else { + console.info("NO validation errors found in policy data"); + if (this.state.policyInstanceType === OnapConstant.microServiceType) { + this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData); + this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup); + LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => { + this.setState({ show: false }); + this.props.history.push('/'); + this.props.loadLoopFunction(this.state.loopCache.getLoopName()); + }); + } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) { + this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData); + this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup); + LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => { + this.setState({ show: false }); + this.props.history.push('/'); + this.props.loadLoopFunction(this.state.loopCache.getLoopName()); + }); + } + } + } + + customValidation(editorData, templateName) { + // method for sub-classes to override with customized validation + return []; + } + + handleClose() { + this.setState({ show: false }); + this.props.history.push('/'); + } + + componentDidMount() { + this.renderJsonEditor(); + } + + componentDidUpdate() { + if (this.state.showSucAlert === true || this.state.showFailAlert === true) { + let modalElement = document.getElementById("policyModal") + if (modalElement) { + modalElement.scrollTo(0, 0); + } + } + } + + createJsonEditor(toscaModel, editorData) { + return new JSONEditor(document.getElementById("editor"), + { schema: toscaModel, + startval: editorData, + theme: 'bootstrap4', + iconlib: 'fontawesome5', + object_layout: 'grid', + disable_properties: false, + disable_edit_json: false, + disable_array_reorder: true, + disable_array_delete_last_row: true, + disable_array_delete_all_rows: false, + array_controls_top: true, + keep_oneof_values: false, + collapsed:true, + show_errors: 'always', + display_required_only: false, + show_opt_in: false, + prompt_before_delete: true, + required_by_default: false + }) + } + + renderJsonEditor() { + console.debug("Rendering PolicyModal ", this.state.policyName); + var toscaModel = {}; + var editorData = {}; + var pdpGroupValues = {}; + var chosenPdpGroupValue, chosenPdpSubgroupValue; + if (this.state.policyInstanceType === OnapConstant.microServiceType) { + toscaModel = this.state.loopCache.getMicroServiceJsonRepresentationForName(this.state.policyName); + editorData = this.state.loopCache.getMicroServicePropertiesForName(this.state.policyName); + pdpGroupValues = this.state.loopCache.getMicroServiceSupportedPdpGroup(this.state.policyName); + chosenPdpGroupValue = this.state.loopCache.getMicroServicePdpGroup(this.state.policyName); + chosenPdpSubgroupValue = this.state.loopCache.getMicroServicePdpSubgroup(this.state.policyName); + } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) { + toscaModel = this.state.loopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName); + editorData = this.state.loopCache.getOperationalPolicyPropertiesForName(this.state.policyName); + pdpGroupValues = this.state.loopCache.getOperationalPolicySupportedPdpGroup(this.state.policyName); + chosenPdpGroupValue = this.state.loopCache.getOperationalPolicyPdpGroup(this.state.policyName); + chosenPdpSubgroupValue = this.state.loopCache.getOperationalPolicyPdpSubgroup(this.state.policyName); + } + + if (toscaModel == null) { + return; + } + + var pdpSubgroupValues = []; + if (typeof(chosenPdpGroupValue) !== "undefined") { + var selectedPdpGroup = pdpGroupValues.filter(entry => (Object.keys(entry)[0] === chosenPdpGroupValue)); + pdpSubgroupValues = selectedPdpGroup[0][chosenPdpGroupValue].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } }); + } + this.setState({ + jsonEditor: this.createJsonEditor(toscaModel,editorData), + pdpGroup: pdpGroupValues, + pdpGroupList: pdpGroupValues.map(entry => { + return { label: Object.keys(entry)[0], value: Object.keys(entry)[0] }; + }), + pdpSubgroupList: pdpSubgroupValues, + chosenPdpGroup: chosenPdpGroupValue, + chosenPdpSubgroup: chosenPdpSubgroupValue + }) + } + + handlePdpGroupChange(e) { + var selectedPdpGroup = this.state.pdpGroup.filter(entry => (Object.keys(entry)[0] === e.value)); + const pdpSubgroupValues = selectedPdpGroup[0][e.value].map((pdpSubgroup) => { return { label: pdpSubgroup, value: pdpSubgroup } }); + if (this.state.chosenPdpGroup !== e.value) { + this.setState({ + chosenPdpGroup: e.value, + chosenPdpSubgroup: '', + pdpSubgroupList: pdpSubgroupValues + }); + } + } + + handlePdpSubgroupChange(e) { + this.setState({ chosenPdpSubgroup: e.value }); + } + + handleRefresh() { + var newLoopCache, toscaModel, editorData; + if (this.state.policyInstanceType === OnapConstant.microServiceType) { + LoopService.refreshMicroServicePolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => { + newLoopCache = new LoopCache(data); + toscaModel = newLoopCache.getMicroServiceJsonRepresentationForName(this.state.policyName); + editorData = newLoopCache.getMicroServicePropertiesForName(this.state.policyName); + document.getElementById("editor").innerHTML = ""; + this.setState({ + loopCache: newLoopCache, + jsonEditor: this.createJsonEditor(toscaModel,editorData), + showSucAlert: true, + showMessage: "Successfully refreshed" + }); + }) + .catch(error => { + console.error("Error while refreshing the Operational Policy Json Representation"); + this.setState({ + showFailAlert: true, + showMessage: "Refreshing of UI failed" + }); + }); + } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) { + LoopService.refreshOperationalPolicyJson(this.state.loopCache.getLoopName(),this.state.policyName).then(data => { + var newLoopCache = new LoopCache(data); + toscaModel = newLoopCache.getOperationalPolicyJsonRepresentationForName(this.state.policyName); + editorData = newLoopCache.getOperationalPolicyPropertiesForName(this.state.policyName); + document.getElementById("editor").innerHTML = ""; + this.setState({ + loopCache: newLoopCache, + jsonEditor: this.createJsonEditor(toscaModel,editorData), + showSucAlert: true, + showMessage: "Successfully refreshed" + }); + }) + .catch(error => { + console.error("Error while refreshing the Operational Policy Json Representation"); + this.setState({ + showFailAlert: true, + showMessage: "Refreshing of UI failed" + }); + }); + } + } + + disableAlert() { + this.setState ({ showSucAlert: false, showFailAlert: false }); + } + + renderPdpGroupDropDown() { + if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) { + return ( + <Form.Group as={Row} controlId="formPlaintextEmail"> + <Form.Label column sm="2">Pdp Group Info</Form.Label> + <Col sm="3"> + <Select value={{ label: this.state.chosenPdpGroup, value: this.state.chosenPdpGroup }} onChange={this.handlePdpGroupChange} options={this.state.pdpGroupList} /> + </Col> + <Col sm="3"> + <Select value={{ label: this.state.chosenPdpSubgroup, value: this.state.chosenPdpSubgroup }} onChange={this.handlePdpSubgroupChange} options={this.state.pdpSubgroupList} /> + </Col> + </Form.Group> + ); + } + } + + renderOpenLoopMessage() { + if(this.state.policyInstanceType === OnapConstant.operationalPolicyType && this.state.loopCache.isOpenLoopTemplate()) { + return ( + "Operational Policy cannot be configured as only Open Loop is supported for this Template!" + ); + } + } + + renderModalTitle() { + return ( + <Modal.Title>Edit the policy</Modal.Title> + ); + } + + renderButton() { + var allElement = [(<Button key="close" variant="secondary" onClick={this.handleClose}> + Close + </Button>)]; + if(this.state.policyInstanceType !== OnapConstant.operationalPolicyType || !this.state.loopCache.isOpenLoopTemplate()) { + allElement.push(( + <Button key="save" variant="primary" disabled={this.readOnly} onClick={this.handleSave}> + Save Changes + </Button> + )); + allElement.push(( + <Button key="refresh" variant="primary" disabled={this.readOnly} onClick={this.handleRefresh}> + Refresh + </Button> + )); + } + return allElement; + } + + render() { + return ( + <ModalStyled size="xl" backdrop="static" keyboard={false} show={this.state.show} onHide={this.handleClose}> + <Modal.Header closeButton> + {this.renderModalTitle()} + </Modal.Header> + <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Modal.Body> + {this.renderOpenLoopMessage()} + <div id="editor" /> + {this.renderPdpGroupDropDown()} + </Modal.Body> + <Modal.Footer> + {this.renderButton()} + </Modal.Footer> + </ModalStyled> + ); + } +} diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js new file mode 100644 index 000000000..1e6fac0a0 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyModal.test.js @@ -0,0 +1,135 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP POLICY-CLAMP + * ================================================================================ + * Copyright (C) 2020-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 { mount } from 'enzyme'; +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(() => { + fetch.resetMocks(); + fetch.mockImplementation(() => { + return Promise.resolve({ + ok: true, + status: 200, + text: () => "OK" + }); + }); + }) + const loopCacheStr = { + "name": "LOOP_Jbv1z_v1_0_ResourceInstanceName1_tca", + "operationalPolicies": [{ + "name": "OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca", + "configurationsJson": { + "operational_policy": { + "controlLoop": {}, + "policies": [] + } + }, + "policyModel": {"policyPdpGroup": {"supportedPdpGroups":[{"monitoring": ["xacml"]}]}}, + "jsonRepresentation" : {"schema": {}} + }] + }; + + const loopCache = new LoopCache(loopCacheStr); + const historyMock = { push: jest.fn() }; + const flushPromises = () => new Promise(setImmediate); + const match = {params: {policyName:"OPERATIONAL_h2NMX_v1_0_ResourceInstanceName1_tca", policyInstanceType: OnapConstant.operationalPolicyType}} + + it('Test handleClose', () => { + const handleClose = jest.spyOn(PolicyModal.prototype,'handleClose'); + const component = mount(<PolicyModal history={historyMock} match={match} loopCache={loopCache}/>) + + component.find('[variant="secondary"]').prop('onClick')(); + + expect(handleClose).toHaveBeenCalledTimes(1); + expect(component.state('show')).toEqual(false); + expect(historyMock.push.mock.calls[0]).toEqual([ '/']); + }); + + it('Test handleSave', async () => { + const loadLoopFunction = jest.fn(); + const handleSave = jest.spyOn(PolicyModal.prototype,'handleSave'); + const component = mount(<PolicyModal history={historyMock} + loopCache={loopCache} match={match} loadLoopFunction={loadLoopFunction} />) + + component.find('[variant="primary"]').get(0).props.onClick(); + await flushPromises(); + component.update(); + + expect(handleSave).toHaveBeenCalledTimes(1); + expect(component.state('show')).toEqual(false); + expect(historyMock.push.mock.calls[0]).toEqual([ '/']); + }); + + it('Test handleRefresh', async () => { + LoopService.refreshOperationalPolicyJson = jest.fn().mockImplementation(() => { + return Promise.resolve(loopCacheStr); + }); + const updateLoopFunction = jest.fn(); + const handleRefresh = jest.spyOn(PolicyModal.prototype,'handleRefresh'); + const component = mount(<PolicyModal loopCache={loopCache} match={match} updateLoopFunction={updateLoopFunction} />) + + component.find('[variant="primary"]').get(1).props.onClick(); + await flushPromises(); + component.update(); + + expect(handleRefresh).toHaveBeenCalledTimes(1); + expect(component.state('show')).toEqual(true); + expect(component.state('showSucAlert')).toEqual(true); + expect(component.state('showMessage')).toEqual("Successfully refreshed"); + }); + + it('Test handlePdpGroupChange', () => { + const component = mount(<PolicyModal loopCache={loopCache} match={match} />) + component.setState({ + "pdpGroup": [{"option1":["subPdp1","subPdp2"]}], + "chosenPdpGroup": "option2" + }); + expect(component.state('chosenPdpGroup')).toEqual("option2"); + + const instance = component.instance(); + const event = {label:"option1", value:"option1"} + instance.handlePdpGroupChange(event); + expect(component.state('chosenPdpGroup')).toEqual("option1"); + expect(component.state('chosenPdpSubgroup')).toEqual(""); + expect(component.state('pdpSubgroupList')).toEqual([{label:"subPdp1", value:"subPdp1"}, {label:"subPdp2", value:"subPdp2"}]); + }); + + it('Test handlePdpSubgroupChange', () => { + const component = mount(<PolicyModal loopCache={loopCache} match={match} />) + + const instance = component.instance(); + const event = {label:"option1", value:"option1"} + instance.handlePdpSubgroupChange(event); + expect(component.state('chosenPdpSubgroup')).toEqual("option1"); + }); + + it('Test the render method', () => { + const component = shallow(<PolicyModal loopCache={loopCache} match={match}/>) + expect(component).toMatchSnapshot(); + }); +});
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js b/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js new file mode 100644 index 000000000..9cd3d4172 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js @@ -0,0 +1,128 @@ +/*- + * ============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,(<Alert variant="danger"><Alert.Heading>{file.name}</Alert.Heading><p>Policy Tosca Model Creation Failure</p><hr/><p>Type: {file.type}</p><p>Size: {file.size}</p></Alert>)] + }; + }); + } else { + this.props.toscaTableUpdateFunction(); + this.setState(state => { + return { + alertMessages: [...state.alertMessages,(<Alert variant="success"><Alert.Heading>{file.name}</Alert.Heading><p>Policy Tosca Model Created Successfully</p><hr/><p>Type: {file.type}</p><p>Size: {file.size}</p></Alert>)] + }; + }); + } + }); + }; + }); + + } + + render() { + return ( + <ModalStyled size="lg" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} > + <Modal.Header closeButton> + <Modal.Title>Create New Policy Tosca Model</Modal.Title> + </Modal.Header> + <Modal.Body> + <Form.Group as={Row} controlId="formPlaintextEmail"> + <Col sm="10"> + <input type="file" multiple accept=".yaml,.yml" id="fileUploadButton" style={{ display: 'none' }} onChange={this.onFileChange} /> + <label htmlFor={'fileUploadButton'}> + <Button color="primary" variant="contained" component="span" + startIcon={ + <SvgIcon fontSize="small"> + <PublishIcon /> + </SvgIcon> + }> + Upload Files + </Button> + <p>(Only YAML files are supported)</p> + </label> + <StyledMessagesDiv> + {this.state.alertMessages} + </StyledMessagesDiv> + </Col> + </Form.Group> + </Modal.Body> + <Modal.Footer> + <Button variant="secondary" onClick={this.handleClose}>Close</Button> + </Modal.Footer> + </ModalStyled> + ); + } +}
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js new file mode 100644 index 000000000..fa83aa245 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.js @@ -0,0 +1,66 @@ +/*- + * ============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 PolicyToscaService from '../../../api/PolicyToscaService'; +import styled from 'styled-components'; +import Button from 'react-bootstrap/Button'; + +const ToscaDiv = styled.div` + background-color: ${props => props.theme.toscaTextareaBackgroundColor}; + text-align: justify; + font-size: ${props => props.theme.toscaTextareaFontSize}; + width: 100%; + height: 30%; +` + +export default class ToscaViewer extends React.Component { + + state = { + toscaData: this.props.toscaData, + yamlPolicyTosca: this.getToscaModelYamlFor(this.props.toscaData), + } + + constructor(props, context) { + super(props, context); + this.getToscaModelYamlFor = this.getToscaModelYamlFor.bind(this); + } + + getToscaModelYamlFor(toscaData) { + PolicyToscaService.getToscaPolicyModelYaml(toscaData["policyModelType"], toscaData["version"]).then(respYamlPolicyTosca => { + this.setState({ + yamlPolicyTosca: respYamlPolicyTosca, + }) + }); + } + + render() { + return ( + <ToscaDiv> + <pre>{this.state.yamlPolicyTosca}</pre> + <Button variant="secondary" title="Create a new policy version from the defined parameters" + onClick={this.handleCreateNewVersion}>Create New Version</Button> + </ToscaDiv> + ); + } +} diff --git a/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js b/runtime/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js new file mode 100644 index 000000000..cc8c59a03 --- /dev/null +++ b/runtime/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(<ToscaViewer toscaData={toscaData}/>); + await PolicyToscaService.getToscaPolicyModelYaml(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js b/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js new file mode 100644 index 000000000..04965352b --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js @@ -0,0 +1,473 @@ +/*- + * ============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 Button from 'react-bootstrap/Button'; +import Modal from 'react-bootstrap/Modal'; +import styled from 'styled-components'; +import AddBox from '@material-ui/icons/AddBox'; +import ArrowDownward from '@material-ui/icons/ArrowDownward'; +import Check from '@material-ui/icons/Check'; +import ChevronLeft from '@material-ui/icons/ChevronLeft'; +import ChevronRight from '@material-ui/icons/ChevronRight'; +import Clear from '@material-ui/icons/Clear'; +import DeleteRoundedIcon from '@material-ui/icons/DeleteRounded'; +import Edit from '@material-ui/icons/Edit'; +import FilterList from '@material-ui/icons/FilterList'; +import FirstPage from '@material-ui/icons/FirstPage'; +import LastPage from '@material-ui/icons/LastPage'; +import Remove from '@material-ui/icons/Remove'; +import SaveAlt from '@material-ui/icons/SaveAlt'; +import Search from '@material-ui/icons/Search'; +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 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 '@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: 800px) { + .modal-xl { + max-width: 96%; + } + } + background-color: transparent; +` +const DetailedRow = styled.div` + margin: 0 auto; + background-color: ${props => props.theme.policyEditorBackgroundColor}; + font-size: ${props => props.theme.policyEditorFontSize}; + width: 97%; + margin-left: auto; + 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 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, + policiesListData: [], + policiesListDataFiltered: [], + toscaModelsListData: [], + toscaModelsListDataFiltered: [], + jsonEditorForPolicy: new Map(), + showSuccessAlert: false, + showFailAlert: false, + showFileSelector: false, + policyColumnsDefinition: [ + { + title: "Policy Name", field: "name", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Policy Version", field: "version", + cellStyle: standardCellStyle, + headerStyle: headerStyle, + }, + { + title: "Policy Type", field: "type", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Policy Type Version", field: "type_version", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Deployable in PDP Group", field: "supportedPdpGroupsString", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Deployed in PDP Group", field: "pdpGroupInfoString", + cellStyle: standardCellStyle, + headerStyle: headerStyle + } + ], + toscaColumnsDefinition: [ + { + title: "Policy Model Type", field: "policyModelType", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Policy Acronym", field: "policyAcronym", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Version", field: "version", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Uploaded By", field: "updatedBy", + cellStyle: standardCellStyle, + headerStyle: headerStyle + }, + { + title: "Uploaded Date", field: "updatedDate", editable: 'never', + cellStyle: standardCellStyle, + headerStyle: headerStyle + } + ], + tableIcons: { + Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />), + Check: forwardRef((props, ref) => <Check {...props} ref={ref} />), + Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />), + Delete: forwardRef((props, ref) => <DeleteRoundedIcon {...props} ref={ref} />), + DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />), + Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />), + Export: forwardRef((props, ref) => <SaveAlt {...props} ref={ref} />), + Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />), + FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />), + LastPage: forwardRef((props, ref) => <LastPage {...props} ref={ref} />), + NextPage: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />), + PreviousPage: forwardRef((props, ref) => <ChevronLeft {...props} ref={ref} />), + ResetSearch: forwardRef((props, ref) => <Clear {...props} ref={ref} />), + Search: forwardRef((props, ref) => <Search {...props} ref={ref} />), + SortArrow: forwardRef((props, ref) => <ArrowDownward {...props} ref={ref} />), + ThirdStateCheck: forwardRef((props, ref) => <Remove {...props} ref={ref} />), + ViewColumn: forwardRef((props, ref) => <ViewColumn {...props} ref={ref} />) + } + }; + + constructor(props, context) { + super(props, context); + this.handleClose = this.handleClose.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(); + } + + 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; + } + + 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; + }); + } + }); + } + + getAllToscaModels() { + PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => { + this.setState({ toscaModelsListData: toscaModelsList, + toscaModelsListDataFiltered: toscaModelsList + }); + }); + } + + getAllPolicies() { + PolicyService.getPoliciesList().then(allPolicies => { + this.generateAdditionalPolicyColumns(allPolicies["policies"]) + this.setState({ policiesListData: allPolicies["policies"], + policiesListDataFiltered: allPolicies["policies"], + }) + }); + + } + + handleClose() { + this.setState({ show: false }); + this.props.history.push('/') + } + + handleDeletePolicy(event, rowData) { + PolicyService.deletePolicy(rowData["type"], rowData["type_version"], rowData["name"],rowData["version"]).then( + respPolicyDeletion => { + if (typeof(respPolicyDeletion) === "undefined") { + //it indicates a failure + this.setState({ + showFailAlert: true, + showMessage: 'Policy Deletion Failure' + }); + } else { + this.setState({ + showSuccessAlert: true, + showMessage: 'Policy successfully Deleted' + }); + this.getAllPolicies(); + } + } + ) + } + + disableAlert() { + this.setState ({ showSuccessAlert: false, showFailAlert: false }); + } + + filterPolicies(prefixForFiltering) { + this.setState({policiesListDataFiltered: this.state.policiesListData.filter(element => element.name.startsWith(prefixForFiltering))}); + } + + filterTosca(prefixForFiltering) { + this.setState({toscaModelsListDataFiltered: this.state.toscaModelsListData.filter(element => element.policyModelType.startsWith(prefixForFiltering))}); + } + + showFileSelector() { + this.setState({showFileSelector:true}); + } + + disableFileSelector() { + this.setState({showFileSelector:false}); + } + + renderPoliciesTab() { + return ( + <Tab eventKey="policies" title="Policies in Policy Framework"> + <Modal.Body> + <div> + <PoliciesTreeViewerDiv> + <PoliciesTreeViewer policiesData={this.state.policiesListData} valueForTreeCreation="name" policiesFilterFunction={this.filterPolicies} /> + </PoliciesTreeViewerDiv> + <MaterialTableDiv> + <MaterialTable + title={"Policies"} + data={this.state.policiesListDataFiltered} + columns={this.state.policyColumnsDefinition} + icons={this.state.tableIcons} + onRowClick={(event, rowData, togglePanel) => togglePanel()} + options={{ + grouping: true, + exportButton: true, + headerStyle:rowHeaderStyle, + actionsColumnIndex: -1 + }} + detailPanel={[ + { + icon: ArrowForwardIosIcon, + tooltip: 'Show Configuration', + render: rowData => { + return ( + <DetailedRow> + <PolicyEditor policyModelType={rowData["type"]} policyModelTypeVersion={rowData["type_version"]} + policyName={rowData["name"]} policyVersion={rowData["version"]} policyProperties={rowData["properties"]} + policiesTableUpdateFunction={this.getAllPolicies} /> + </DetailedRow> + ) + }, + }, + { + icon: DehazeIcon, + openIcon: DehazeIcon, + tooltip: 'Show Raw Data', + render: rowData => { + return ( + <DetailedRow> + <pre>{JSON.stringify(rowData, null, 2)}</pre> + </DetailedRow> + ) + }, + }, + { + icon: PublishIcon, + openIcon: PublishIcon, + tooltip: 'PDP Group Deployment', + render: rowData => { + return ( + <DetailedRow> + <PolicyDeploymentEditor policyData={rowData} policiesTableUpdateFunction={this.getAllPolicies} /> + </DetailedRow> + ) + }, + } + ]} + actions={[ + { + icon: DeleteRoundedIcon, + tooltip: 'Delete Policy', + onClick: (event, rowData) => this.handleDeletePolicy(event, rowData) + } + ]} + /> + </MaterialTableDiv> + </div> + </Modal.Body> + </Tab> + ); + } + + renderToscaTab() { + return ( + <Tab eventKey="tosca models" title="Tosca Models in Policy Framework"> + <Modal.Body> + <div> + <PoliciesTreeViewerDiv> + <PoliciesTreeViewer policiesData={this.state.toscaModelsListData} valueForTreeCreation="policyModelType" policiesFilterFunction={this.filterTosca} /> + </PoliciesTreeViewerDiv> + <MaterialTableDiv> + <MaterialTable + title={"Tosca Models"} + data={this.state.toscaModelsListDataFiltered} + columns={this.state.toscaColumnsDefinition} + icons={this.state.tableIcons} + onRowClick={(event, rowData, togglePanel) => togglePanel()} + options={{ + grouping: true, + exportButton: true, + headerStyle:rowHeaderStyle, + actionsColumnIndex: -1 + }} + actions={[ + { + icon: AddIcon, + tooltip: 'Add New Tosca Model', + isFreeAction: true, + onClick: () => this.showFileSelector() + } + ]} + detailPanel={[ + { + icon: ArrowForwardIosIcon, + tooltip: 'Show Tosca', + render: rowData => { + return ( + <DetailedRow> + <ToscaViewer toscaData={rowData} /> + </DetailedRow> + ) + }, + }, + { + icon: DehazeIcon, + openIcon: DehazeIcon, + tooltip: 'Show Raw Data', + render: rowData => { + return ( + <DetailedRow> + <pre>{JSON.stringify(rowData, null, 2)}</pre> + </DetailedRow> + ) + }, + }, + { + icon: AddIcon, + openIcon: AddIcon, + tooltip: 'Create a policy from this model', + render: rowData => { + return ( + <DetailedRow> + <PolicyEditor policyModelType={rowData["policyModelType"]} policyModelTypeVersion={rowData["version"]} policyProperties={{}} policiesTableUpdateFunction={this.getAllPolicies} /> + </DetailedRow> + ) + }, + }, + ]} + /> + </MaterialTableDiv> + </div> + </Modal.Body> + </Tab> + ); + } + + render() { + return ( + <React.Fragment> + <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}> + <Modal.Header closeButton> + </Modal.Header> + <Tabs id="controlled-tab-example" activeKey={this.state.key} onSelect={key => this.setState({ key, selectedRowData: {} })}> + {this.renderPoliciesTab()} + {this.renderToscaTab()} + </Tabs> + <Alert variant="success" show={this.state.showSuccessAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible> + <DivWhiteSpaceStyled> + {this.state.showMessage} + </DivWhiteSpaceStyled> + </Alert> + <Modal.Footer> + <Button variant="secondary" onClick={this.handleClose}>Close</Button> + </Modal.Footer> + </ModalStyled> + <PolicyToscaFileSelector show={this.state.showFileSelector} disableFunction={this.disableFileSelector} toscaTableUpdateFunction={this.getAllToscaModels}/> + </React.Fragment> + ); + } + }
\ No newline at end of file diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap new file mode 100644 index 000000000..959b52a36 --- /dev/null +++ b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap @@ -0,0 +1,788 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Verify PolicyEditor Test the render method 1`] = ` +<PolicyEditor + policiesTableUpdateFunction={[Function]} + policyModelType="onap.policies.monitoring.tcagen2" + policyModelTypeVersion="1.0.0" + policyName="org.onap.new" + policyProperties={ + Object { + "tca.policy": Object { + "domain": "measurementsForVfScaling", + "metricsPerEventName": Array [ + Object { + "controlLoopSchemaType": "VM", + "eventName": "vLoadBalancer", + "policyName": "DCAE.Config_tca-hi-lo", + "policyScope": "DCAE", + "policyVersion": "v0.0.1", + "thresholds": Array [ + Object { + "closedLoopControlName": "LOOP_test", + "closedLoopEventStatus": "ONSET", + "direction": "LESS_OR_EQUAL", + "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta", + "severity": "MAJOR", + "thresholdValue": 200, + "version": "1.0.2", + }, + ], + }, + ], + }, + } + } + policyVersion="1.0.0" +> + <styled.div> + <div + className="sc-dlfnbm iSTbVM" + > + <Alert + closeLabel="Close alert" + dismissible={true} + onClose={[Function]} + show={false} + transition={ + Object { + "$$typeof": Symbol(react.forward_ref), + "defaultProps": Object { + "appear": false, + "in": false, + "mountOnEnter": false, + "timeout": 300, + "unmountOnExit": false, + }, + "render": [Function], + } + } + variant="success" + > + <Fade + appear={false} + in={false} + mountOnEnter={false} + timeout={300} + unmountOnExit={true} + > + <Transition + addEndListener={[Function]} + appear={false} + enter={true} + exit={true} + in={false} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={300} + unmountOnExit={true} + /> + </Fade> + </Alert> + <Alert + closeLabel="Close alert" + dismissible={true} + onClose={[Function]} + show={false} + transition={ + Object { + "$$typeof": Symbol(react.forward_ref), + "defaultProps": Object { + "appear": false, + "in": false, + "mountOnEnter": false, + "timeout": 300, + "unmountOnExit": false, + }, + "render": [Function], + } + } + variant="danger" + > + <Fade + appear={false} + in={false} + mountOnEnter={false} + timeout={300} + unmountOnExit={true} + > + <Transition + addEndListener={[Function]} + appear={false} + enter={true} + exit={true} + in={false} + mountOnEnter={false} + onEnter={[Function]} + onEntered={[Function]} + onEntering={[Function]} + onExit={[Function]} + onExited={[Function]} + onExiting={[Function]} + timeout={300} + unmountOnExit={true} + /> + </Fade> + </Alert> + <WithStyles(ForwardRef(TextField)) + defaultValue="org.onap.new" + id="policyName" + label="Required" + onChange={[Function]} + required={true} + size="small" + variant="outlined" + > + <ForwardRef(TextField) + classes={ + Object { + "root": "MuiTextField-root", + } + } + defaultValue="org.onap.new" + id="policyName" + label="Required" + onChange={[Function]} + required={true} + size="small" + variant="outlined" + > + <WithStyles(ForwardRef(FormControl)) + className="MuiTextField-root" + color="primary" + disabled={false} + error={false} + fullWidth={false} + required={true} + size="small" + variant="outlined" + > + <ForwardRef(FormControl) + className="MuiTextField-root" + classes={ + Object { + "fullWidth": "MuiFormControl-fullWidth", + "marginDense": "MuiFormControl-marginDense", + "marginNormal": "MuiFormControl-marginNormal", + "root": "MuiFormControl-root", + } + } + color="primary" + disabled={false} + error={false} + fullWidth={false} + required={true} + size="small" + variant="outlined" + > + <div + className="MuiFormControl-root MuiTextField-root" + > + <WithStyles(ForwardRef(InputLabel)) + htmlFor="policyName" + id="policyName-label" + > + <ForwardRef(InputLabel) + classes={ + Object { + "animated": "MuiInputLabel-animated", + "asterisk": "MuiInputLabel-asterisk", + "disabled": "Mui-disabled", + "error": "Mui-error", + "filled": "MuiInputLabel-filled", + "focused": "Mui-focused", + "formControl": "MuiInputLabel-formControl", + "marginDense": "MuiInputLabel-marginDense", + "outlined": "MuiInputLabel-outlined", + "required": "Mui-required", + "root": "MuiInputLabel-root", + "shrink": "MuiInputLabel-shrink", + } + } + htmlFor="policyName" + id="policyName-label" + > + <WithStyles(ForwardRef(FormLabel)) + className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined" + classes={ + Object { + "asterisk": "MuiInputLabel-asterisk", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "required": "Mui-required", + } + } + data-shrink={true} + htmlFor="policyName" + id="policyName-label" + > + <ForwardRef(FormLabel) + className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined" + classes={ + Object { + "asterisk": "MuiFormLabel-asterisk MuiInputLabel-asterisk", + "colorSecondary": "MuiFormLabel-colorSecondary", + "disabled": "Mui-disabled Mui-disabled", + "error": "Mui-error Mui-error", + "filled": "MuiFormLabel-filled", + "focused": "Mui-focused Mui-focused", + "required": "Mui-required Mui-required", + "root": "MuiFormLabel-root", + } + } + data-shrink={true} + htmlFor="policyName" + id="policyName-label" + > + <label + className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required" + data-shrink={true} + htmlFor="policyName" + id="policyName-label" + > + Required + <span + aria-hidden={true} + className="MuiFormLabel-asterisk MuiInputLabel-asterisk" + > + + * + </span> + </label> + </ForwardRef(FormLabel)> + </WithStyles(ForwardRef(FormLabel))> + </ForwardRef(InputLabel)> + </WithStyles(ForwardRef(InputLabel))> + <WithStyles(ForwardRef(OutlinedInput)) + autoFocus={false} + defaultValue="org.onap.new" + fullWidth={false} + id="policyName" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + multiline={false} + onChange={[Function]} + > + <ForwardRef(OutlinedInput) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "input": "MuiOutlinedInput-input", + "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart", + "inputMarginDense": "MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiOutlinedInput-inputMultiline", + "marginDense": "MuiOutlinedInput-marginDense", + "multiline": "MuiOutlinedInput-multiline", + "notchedOutline": "MuiOutlinedInput-notchedOutline", + "root": "MuiOutlinedInput-root", + } + } + defaultValue="org.onap.new" + fullWidth={false} + id="policyName" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + multiline={false} + onChange={[Function]} + > + <WithStyles(ForwardRef(InputBase)) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "input": "MuiOutlinedInput-input", + "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart", + "inputMarginDense": "MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiOutlinedInput-inputMultiline", + "marginDense": "MuiOutlinedInput-marginDense", + "multiline": "MuiOutlinedInput-multiline", + "notchedOutline": null, + "root": "MuiOutlinedInput-root", + } + } + defaultValue="org.onap.new" + fullWidth={false} + id="policyName" + inputComponent="input" + multiline={false} + onChange={[Function]} + renderSuffix={[Function]} + type="text" + > + <ForwardRef(InputBase) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiInputBase-adornedEnd MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiInputBase-adornedStart MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiInputBase-colorSecondary MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled Mui-disabled", + "error": "Mui-error Mui-error", + "focused": "Mui-focused Mui-focused", + "formControl": "MuiInputBase-formControl", + "fullWidth": "MuiInputBase-fullWidth", + "input": "MuiInputBase-input MuiOutlinedInput-input", + "inputAdornedEnd": "MuiInputBase-inputAdornedEnd MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiInputBase-inputAdornedStart MuiOutlinedInput-inputAdornedStart", + "inputHiddenLabel": "MuiInputBase-inputHiddenLabel", + "inputMarginDense": "MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiInputBase-inputMultiline MuiOutlinedInput-inputMultiline", + "inputTypeSearch": "MuiInputBase-inputTypeSearch", + "marginDense": "MuiInputBase-marginDense MuiOutlinedInput-marginDense", + "multiline": "MuiInputBase-multiline MuiOutlinedInput-multiline", + "root": "MuiInputBase-root MuiOutlinedInput-root", + } + } + defaultValue="org.onap.new" + fullWidth={false} + id="policyName" + inputComponent="input" + multiline={false} + onChange={[Function]} + renderSuffix={[Function]} + type="text" + > + <div + className="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-formControl MuiInputBase-marginDense MuiOutlinedInput-marginDense" + onClick={[Function]} + > + <input + aria-invalid={false} + autoFocus={false} + className="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense" + defaultValue="org.onap.new" + disabled={false} + id="policyName" + onAnimationStart={[Function]} + onBlur={[Function]} + onChange={[Function]} + onFocus={[Function]} + required={true} + type="text" + /> + <WithStyles(ForwardRef(NotchedOutline)) + className="MuiOutlinedInput-notchedOutline" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + labelWidth={0} + notched={true} + > + <ForwardRef(NotchedOutline) + className="MuiOutlinedInput-notchedOutline" + classes={ + Object { + "legend": "PrivateNotchedOutline-legend-2", + "legendLabelled": "PrivateNotchedOutline-legendLabelled-3", + "legendNotched": "PrivateNotchedOutline-legendNotched-4", + "root": "PrivateNotchedOutline-root-1", + } + } + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + labelWidth={0} + notched={true} + > + <fieldset + aria-hidden={true} + className="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline" + > + <legend + className="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4" + > + <span> + Required + * + </span> + </legend> + </fieldset> + </ForwardRef(NotchedOutline)> + </WithStyles(ForwardRef(NotchedOutline))> + </div> + </ForwardRef(InputBase)> + </WithStyles(ForwardRef(InputBase))> + </ForwardRef(OutlinedInput)> + </WithStyles(ForwardRef(OutlinedInput))> + </div> + </ForwardRef(FormControl)> + </WithStyles(ForwardRef(FormControl))> + </ForwardRef(TextField)> + </WithStyles(ForwardRef(TextField))> + <WithStyles(ForwardRef(TextField)) + defaultValue="1.0.0" + id="policyVersion" + label="Required" + onChange={[Function]} + required={true} + size="small" + variant="outlined" + > + <ForwardRef(TextField) + classes={ + Object { + "root": "MuiTextField-root", + } + } + defaultValue="1.0.0" + id="policyVersion" + label="Required" + onChange={[Function]} + required={true} + size="small" + variant="outlined" + > + <WithStyles(ForwardRef(FormControl)) + className="MuiTextField-root" + color="primary" + disabled={false} + error={false} + fullWidth={false} + required={true} + size="small" + variant="outlined" + > + <ForwardRef(FormControl) + className="MuiTextField-root" + classes={ + Object { + "fullWidth": "MuiFormControl-fullWidth", + "marginDense": "MuiFormControl-marginDense", + "marginNormal": "MuiFormControl-marginNormal", + "root": "MuiFormControl-root", + } + } + color="primary" + disabled={false} + error={false} + fullWidth={false} + required={true} + size="small" + variant="outlined" + > + <div + className="MuiFormControl-root MuiTextField-root" + > + <WithStyles(ForwardRef(InputLabel)) + htmlFor="policyVersion" + id="policyVersion-label" + > + <ForwardRef(InputLabel) + classes={ + Object { + "animated": "MuiInputLabel-animated", + "asterisk": "MuiInputLabel-asterisk", + "disabled": "Mui-disabled", + "error": "Mui-error", + "filled": "MuiInputLabel-filled", + "focused": "Mui-focused", + "formControl": "MuiInputLabel-formControl", + "marginDense": "MuiInputLabel-marginDense", + "outlined": "MuiInputLabel-outlined", + "required": "Mui-required", + "root": "MuiInputLabel-root", + "shrink": "MuiInputLabel-shrink", + } + } + htmlFor="policyVersion" + id="policyVersion-label" + > + <WithStyles(ForwardRef(FormLabel)) + className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined" + classes={ + Object { + "asterisk": "MuiInputLabel-asterisk", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "required": "Mui-required", + } + } + data-shrink={true} + htmlFor="policyVersion" + id="policyVersion-label" + > + <ForwardRef(FormLabel) + className="MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined" + classes={ + Object { + "asterisk": "MuiFormLabel-asterisk MuiInputLabel-asterisk", + "colorSecondary": "MuiFormLabel-colorSecondary", + "disabled": "Mui-disabled Mui-disabled", + "error": "Mui-error Mui-error", + "filled": "MuiFormLabel-filled", + "focused": "Mui-focused Mui-focused", + "required": "Mui-required Mui-required", + "root": "MuiFormLabel-root", + } + } + data-shrink={true} + htmlFor="policyVersion" + id="policyVersion-label" + > + <label + className="MuiFormLabel-root MuiInputLabel-root MuiInputLabel-formControl MuiInputLabel-animated MuiInputLabel-shrink MuiInputLabel-marginDense MuiInputLabel-outlined MuiFormLabel-filled Mui-required Mui-required" + data-shrink={true} + htmlFor="policyVersion" + id="policyVersion-label" + > + Required + <span + aria-hidden={true} + className="MuiFormLabel-asterisk MuiInputLabel-asterisk" + > + + * + </span> + </label> + </ForwardRef(FormLabel)> + </WithStyles(ForwardRef(FormLabel))> + </ForwardRef(InputLabel)> + </WithStyles(ForwardRef(InputLabel))> + <WithStyles(ForwardRef(OutlinedInput)) + autoFocus={false} + defaultValue="1.0.0" + fullWidth={false} + id="policyVersion" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + multiline={false} + onChange={[Function]} + > + <ForwardRef(OutlinedInput) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "input": "MuiOutlinedInput-input", + "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart", + "inputMarginDense": "MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiOutlinedInput-inputMultiline", + "marginDense": "MuiOutlinedInput-marginDense", + "multiline": "MuiOutlinedInput-multiline", + "notchedOutline": "MuiOutlinedInput-notchedOutline", + "root": "MuiOutlinedInput-root", + } + } + defaultValue="1.0.0" + fullWidth={false} + id="policyVersion" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + multiline={false} + onChange={[Function]} + > + <WithStyles(ForwardRef(InputBase)) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled", + "error": "Mui-error", + "focused": "Mui-focused", + "input": "MuiOutlinedInput-input", + "inputAdornedEnd": "MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiOutlinedInput-inputAdornedStart", + "inputMarginDense": "MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiOutlinedInput-inputMultiline", + "marginDense": "MuiOutlinedInput-marginDense", + "multiline": "MuiOutlinedInput-multiline", + "notchedOutline": null, + "root": "MuiOutlinedInput-root", + } + } + defaultValue="1.0.0" + fullWidth={false} + id="policyVersion" + inputComponent="input" + multiline={false} + onChange={[Function]} + renderSuffix={[Function]} + type="text" + > + <ForwardRef(InputBase) + autoFocus={false} + classes={ + Object { + "adornedEnd": "MuiInputBase-adornedEnd MuiOutlinedInput-adornedEnd", + "adornedStart": "MuiInputBase-adornedStart MuiOutlinedInput-adornedStart", + "colorSecondary": "MuiInputBase-colorSecondary MuiOutlinedInput-colorSecondary", + "disabled": "Mui-disabled Mui-disabled", + "error": "Mui-error Mui-error", + "focused": "Mui-focused Mui-focused", + "formControl": "MuiInputBase-formControl", + "fullWidth": "MuiInputBase-fullWidth", + "input": "MuiInputBase-input MuiOutlinedInput-input", + "inputAdornedEnd": "MuiInputBase-inputAdornedEnd MuiOutlinedInput-inputAdornedEnd", + "inputAdornedStart": "MuiInputBase-inputAdornedStart MuiOutlinedInput-inputAdornedStart", + "inputHiddenLabel": "MuiInputBase-inputHiddenLabel", + "inputMarginDense": "MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense", + "inputMultiline": "MuiInputBase-inputMultiline MuiOutlinedInput-inputMultiline", + "inputTypeSearch": "MuiInputBase-inputTypeSearch", + "marginDense": "MuiInputBase-marginDense MuiOutlinedInput-marginDense", + "multiline": "MuiInputBase-multiline MuiOutlinedInput-multiline", + "root": "MuiInputBase-root MuiOutlinedInput-root", + } + } + defaultValue="1.0.0" + fullWidth={false} + id="policyVersion" + inputComponent="input" + multiline={false} + onChange={[Function]} + renderSuffix={[Function]} + type="text" + > + <div + className="MuiInputBase-root MuiOutlinedInput-root MuiInputBase-formControl MuiInputBase-marginDense MuiOutlinedInput-marginDense" + onClick={[Function]} + > + <input + aria-invalid={false} + autoFocus={false} + className="MuiInputBase-input MuiOutlinedInput-input MuiInputBase-inputMarginDense MuiOutlinedInput-inputMarginDense" + defaultValue="1.0.0" + disabled={false} + id="policyVersion" + onAnimationStart={[Function]} + onBlur={[Function]} + onChange={[Function]} + onFocus={[Function]} + required={true} + type="text" + /> + <WithStyles(ForwardRef(NotchedOutline)) + className="MuiOutlinedInput-notchedOutline" + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + labelWidth={0} + notched={true} + > + <ForwardRef(NotchedOutline) + className="MuiOutlinedInput-notchedOutline" + classes={ + Object { + "legend": "PrivateNotchedOutline-legend-2", + "legendLabelled": "PrivateNotchedOutline-legendLabelled-3", + "legendNotched": "PrivateNotchedOutline-legendNotched-4", + "root": "PrivateNotchedOutline-root-1", + } + } + label={ + <React.Fragment> + Required + * + </React.Fragment> + } + labelWidth={0} + notched={true} + > + <fieldset + aria-hidden={true} + className="PrivateNotchedOutline-root-1 MuiOutlinedInput-notchedOutline" + > + <legend + className="PrivateNotchedOutline-legendLabelled-3 PrivateNotchedOutline-legendNotched-4" + > + <span> + Required + * + </span> + </legend> + </fieldset> + </ForwardRef(NotchedOutline)> + </WithStyles(ForwardRef(NotchedOutline))> + </div> + </ForwardRef(InputBase)> + </WithStyles(ForwardRef(InputBase))> + </ForwardRef(OutlinedInput)> + </WithStyles(ForwardRef(OutlinedInput))> + </div> + </ForwardRef(FormControl)> + </WithStyles(ForwardRef(FormControl))> + </ForwardRef(TextField)> + </WithStyles(ForwardRef(TextField))> + <Button + active={false} + disabled={false} + onClick={[Function]} + title="Create a new policy version from the defined parameters" + variant="secondary" + > + <button + className="btn btn-secondary" + disabled={false} + onClick={[Function]} + title="Create a new policy version from the defined parameters" + type="button" + > + Create New Version + </button> + </Button> + <styled.div + id="onap.policies.monitoring.tcagen2_1.0.0_org.onap.new_1.0.0" + title="Policy Properties" + > + <div + className="sc-gsTCUz dAYWPx" + id="onap.policies.monitoring.tcagen2_1.0.0_org.onap.new_1.0.0" + title="Policy Properties" + /> + </styled.div> + </div> + </styled.div> +</PolicyEditor> +`; diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap new file mode 100644 index 000000000..8b1261b1c --- /dev/null +++ b/runtime/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`] = ` +<Styled(Modal) + backdrop="static" + keyboard={false} + onHide={[Function]} + show={true} + size="xl" +> + <ModalHeader + closeButton={true} + closeLabel="Close" + > + <ModalTitle> + Edit the policy + </ModalTitle> + </ModalHeader> + <Alert + closeLabel="Close alert" + dismissible={true} + onClose={[Function]} + show={false} + transition={ + Object { + "$$typeof": Symbol(react.forward_ref), + "defaultProps": Object { + "appear": false, + "in": false, + "mountOnEnter": false, + "timeout": 300, + "unmountOnExit": false, + }, + "render": [Function], + } + } + variant="success" + > + <styled.div /> + </Alert> + <Alert + closeLabel="Close alert" + dismissible={true} + onClose={[Function]} + show={false} + transition={ + Object { + "$$typeof": Symbol(react.forward_ref), + "defaultProps": Object { + "appear": false, + "in": false, + "mountOnEnter": false, + "timeout": 300, + "unmountOnExit": false, + }, + "render": [Function], + } + } + variant="danger" + > + <styled.div /> + </Alert> + <ModalBody> + <div + id="editor" + /> + <FormGroup + as={ + Object { + "$$typeof": Symbol(react.forward_ref), + "defaultProps": Object { + "noGutters": false, + }, + "render": [Function], + } + } + controlId="formPlaintextEmail" + > + <FormLabel + column={true} + sm="2" + srOnly={false} + > + Pdp Group Info + </FormLabel> + <Col + sm="3" + > + <StateManager + defaultInputValue="" + defaultMenuIsOpen={false} + defaultValue={null} + onChange={[Function]} + options={ + Array [ + Object { + "label": "monitoring", + "value": "monitoring", + }, + ] + } + value={ + Object { + "label": undefined, + "value": undefined, + } + } + /> + </Col> + <Col + sm="3" + > + <StateManager + defaultInputValue="" + defaultMenuIsOpen={false} + defaultValue={null} + onChange={[Function]} + options={Array []} + value={ + Object { + "label": undefined, + "value": undefined, + } + } + /> + </Col> + </FormGroup> + </ModalBody> + <ModalFooter> + <Button + active={false} + disabled={false} + key="close" + onClick={[Function]} + variant="secondary" + > + Close + </Button> + <Button + active={false} + disabled={false} + key="save" + onClick={[Function]} + variant="primary" + > + Save Changes + </Button> + <Button + active={false} + disabled={false} + key="refresh" + onClick={[Function]} + variant="primary" + > + Refresh + </Button> + </ModalFooter> +</Styled(Modal)> +`; diff --git a/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap b/runtime/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap new file mode 100644 index 000000000..61fb4850d --- /dev/null +++ b/runtime/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`] = ` +<styled.div> + <pre> + 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 + + </pre> + <Button + active={false} + disabled={false} + title="Create a new policy version from the defined parameters" + variant="secondary" + > + Create New Version + </Button> +</styled.div> +`; diff --git a/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.json new file mode 100644 index 000000000..3b001b384 --- /dev/null +++ b/runtime/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/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml b/runtime/ui-react/src/components/dialogs/Policy/toscaData.test.yaml new file mode 100644 index 000000000..15a3cec35 --- /dev/null +++ b/runtime/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 |