aboutsummaryrefslogtreecommitdiffstats
path: root/gui-clamp
diff options
context:
space:
mode:
Diffstat (limited to 'gui-clamp')
-rw-r--r--gui-clamp/ui-react-lib/libIndex.js4
-rw-r--r--gui-clamp/ui-react/package.json18
-rw-r--r--gui-clamp/ui-react/src/api/PoliciesListCache.js34
-rw-r--r--gui-clamp/ui-react/src/api/PolicyService.js56
-rw-r--r--gui-clamp/ui-react/src/api/PolicyToscaService.js56
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js7
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js21
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js7
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap9
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js109
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js178
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js29
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js72
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js21
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js11
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js133
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js7
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js54
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js434
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap788
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap159
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap30
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json179
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml13
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js4
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js2
-rw-r--r--gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap2
-rw-r--r--gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js7
-rw-r--r--gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap1
-rw-r--r--gui-clamp/ui-react/src/components/loop_viewer/status/LoopStatus.js7
-rw-r--r--gui-clamp/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap2
-rw-r--r--gui-clamp/ui-react/src/components/loop_viewer/svg/SvgGenerator.js388
-rw-r--r--gui-clamp/ui-react/src/setupTests.js4
33 files changed, 2275 insertions, 571 deletions
diff --git a/gui-clamp/ui-react-lib/libIndex.js b/gui-clamp/ui-react-lib/libIndex.js
index 46c331f..2a91ebf 100644
--- a/gui-clamp/ui-react-lib/libIndex.js
+++ b/gui-clamp/ui-react-lib/libIndex.js
@@ -26,7 +26,6 @@ export { default as CreateLoopModal } from './src/components/dialogs/Loop/Create
export { default as DeployLoopModal } from './src/components/dialogs/Loop/DeployLoopModal';
export { default as LoopActionService } from './src/api/LoopActionService';
export { default as LoopCache } from './src/api/LoopCache';
-export { default as PoliciesListCache } from './src/api/PoliciesListCache';
export { default as LoopLogs } from './src/components/loop_viewer/logs/LoopLogs';
export { default as LoopPropertiesModal } from './src/components/dialogs/Loop/LoopPropertiesModal';
export { default as LoopService } from './src/api/LoopService';
@@ -52,3 +51,6 @@ export { default as UserInfoModal } from './src/components/dialogs/UserInfoModal
export { default as UserService } from './src/api/UserService';
export { default as ViewLoopTemplatesModal } from './src/components/dialogs/Tosca/ViewLoopTemplatesModal';
export { default as ViewAllPolicies } from './src/components/dialogs/Policy/ViewAllPolicies';
+export { default as PolicyDeploymentEditor } from './src/components/dialogs/Policy/PolicyDeploymentEditor';
+export { default as PoliciesTreeViewer } from './src/components/dialogs/Policy/PoliciesTreeViewer';
+export { default as PolicyToscaFileSelector } from './src/components/dialogs/Policy/PolicyToscaFileSelector';
diff --git a/gui-clamp/ui-react/package.json b/gui-clamp/ui-react/package.json
index 8d11044..fd3dc0a 100644
--- a/gui-clamp/ui-react/package.json
+++ b/gui-clamp/ui-react/package.json
@@ -27,8 +27,8 @@
"dependencies": {
"@json-editor/json-editor": "2.5.2",
"@fortawesome/fontawesome-free": "5.15.2",
- "react": "17.0.1",
- "react-dom": "17.0.1",
+ "react": "17.0.2",
+ "react-dom": "17.0.2",
"react-scripts": "4.0.3",
"react-bootstrap": "1.5.2",
"bootstrap-css-only": "4.3.1",
@@ -36,9 +36,10 @@
"react-router-dom": "5.2.0",
"@material-ui/core": "4.11.3",
"@material-ui/icons": "4.11.2",
+ "@material-ui/pickers": "3.3.10",
+ "@material-ui/lab": "4.0.0-alpha.57",
"material-table": "1.68.1",
- "react-select": "4.2.1",
- "react-uuid": "1.0.2"
+ "react-select": "4.2.1"
},
"devDependencies": {
"jest": "26.6.0",
@@ -47,9 +48,10 @@
"@babel/preset-react": "7.12.13",
"@babel/plugin-proposal-class-properties": "7.13.0",
"enzyme": "3.11.0",
- "enzyme-adapter-react-17-updated": "1.0.2",
+ "@wojtekmaj/enzyme-adapter-react-17": "0.6.1",
"enzyme-to-json": "3.6.1",
- "jest-fetch-mock": "3.0.3"
+ "jest-fetch-mock": "3.0.3",
+ "jest-canvas-mock": "2.3.1"
},
"browserslist": [
">0.2%",
@@ -71,7 +73,8 @@
"\\.(css|png)$": "identity-obj-proxy"
},
"setupFiles": [
- "./src/setupTests.js"
+ "./src/setupTests.js",
+ "jest-canvas-mock"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
@@ -95,4 +98,3 @@
]
}
}
-
diff --git a/gui-clamp/ui-react/src/api/PoliciesListCache.js b/gui-clamp/ui-react/src/api/PoliciesListCache.js
deleted file mode 100644
index 265dab4..0000000
--- a/gui-clamp/ui-react/src/api/PoliciesListCache.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-
- * ============LICENSE_START=======================================================
- * ONAP CLAMP
- * ================================================================================
- * Copyright (C) 2021 AT&T Intellectual Property. All rights
- * reserved.
- * ================================================================================
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ============LICENSE_END============================================
- * ===================================================================
- *
- */
-
-export default class PoliciesListCache {
- policiesJsonCache;
-
- constructor(policiesJson) {
- this.policiesJsonCache = policiesJson;
- }
-
- getAllPolicies() {
- return this.policiesJsonCache["policies"];
- }
-}
diff --git a/gui-clamp/ui-react/src/api/PolicyService.js b/gui-clamp/ui-react/src/api/PolicyService.js
index 046f789..cf4f0fd 100644
--- a/gui-clamp/ui-react/src/api/PolicyService.js
+++ b/gui-clamp/ui-react/src/api/PolicyService.js
@@ -41,7 +41,7 @@ export default class PolicyService {
console.error("getPoliciesList error occurred ", error);
alert("getPoliciesList error occurred " + error);
return undefined;
- })
+ });
}
static createNewPolicy(policyModelType, policyModelVersion, policyName, policyVersion, policyJson) {
@@ -95,4 +95,58 @@ export default class PolicyService {
return undefined;
});
}
+
+ static updatePdpDeployment(pdpOperationsList) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/pdpDeployment', {
+ method: 'PUT',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "application/json"
+ },
+ body: JSON.stringify(pdpOperationsList)
+ })
+ .then(function (response) {
+ console.debug("updatePdpDeployment response received: ", response.status);
+ if (response.ok) {
+ console.info("updatePdpDeployment query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("updatePdpDeployment error occurred ", error);
+ alert("updatePdpDeployment error occurred " + error);
+ return undefined;
+ });
+ }
+
+ static sendNewPolicyModel(newPolicyModel) {
+ return fetch(window.location.pathname + 'restservices/clds/v2/policies/policytype', {
+ method: 'POST',
+ credentials: 'same-origin',
+ headers: {
+ "Content-Type": "plain/text"
+ },
+ body: newPolicyModel
+ })
+ .then(function (response) {
+ console.debug("sendNewPolicyModel response received: ", response.status);
+ if (response.ok) {
+ console.info("sendNewPolicyModel query successful");
+ return response.text();
+ } else {
+ return response.text().then(responseBody => {
+ throw new Error("HTTP " + response.status + "," + responseBody);
+ })
+ }
+ })
+ .catch(function (error) {
+ console.error("sendNewPolicyModel error occurred ", error);
+ alert("sendNewPolicyModel error occurred " + error);
+ return undefined;
+ });
+ }
}
diff --git a/gui-clamp/ui-react/src/api/PolicyToscaService.js b/gui-clamp/ui-react/src/api/PolicyToscaService.js
index b5282f9..6c74149 100644
--- a/gui-clamp/ui-react/src/api/PolicyToscaService.js
+++ b/gui-clamp/ui-react/src/api/PolicyToscaService.js
@@ -77,60 +77,4 @@ export default class PolicyToscaService {
return {};
});
}
-
- static createPolicyModelFromToscaModel(jsonData) {
- return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels', {
- method: 'POST',
- credentials: 'same-origin',
- headers: {
- "Content-Type": "a",
- },
- body: JSON.stringify(jsonData)
- })
- .then(function (response) {
- console.debug("createPolicyModelFromToscaModel response received: ", response.status);
- if (response.ok) {
- var message = {
- status: response.status,
- message: 'Tosca Policy Model successfully uploaded'
- };
- return message;
- } else {
- console.error("createPolicyModelFromToscaModel failed");
- return response.text();
- }
- })
- .catch(function (error) {
- console.error("createPolicyModelFromToscaModel error received", error);
- return "";
- });
- }
-
- static updatePolicyModelTosca(policyModelType, policyModelVersion, jsonData) {
- return fetch(window.location.pathname + 'restservices/clds/v2/policyToscaModels/' + policyModelType + '/' + policyModelVersion, {
- method: 'PUT',
- credentials: 'same-origin',
- headers: {
- "Content-Type": "a",
- },
- body: JSON.stringify(jsonData)
- })
- .then(function (response) {
- console.debug("updatePolicyModelTosca response received: ", response.status);
- if (response.ok) {
- var message = {
- status: response.status,
- message: 'Tosca Policy Model successfully uploaded'
- };
- return message;
- } else {
- console.error("updatePolicyModelTosca failed");
- return response.text();
- }
- })
- .catch(function (error) {
- console.error("updatePolicyModelTosca error received", error);
- return "";
- });
- }
}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js b/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js
index 401bb6a..3d94833 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Loop/CreateLoopModal.test.js
@@ -26,6 +26,13 @@ import CreateLoopModal from './CreateLoopModal';
import LoopService from '../../../api/LoopService';
import TemplateService from '../../../api/TemplateService';
+let errorMessage = '';
+window.alert = jest.fn().mockImplementation((mesg) => {
+ errorMessage = mesg;
+ return
+});
+
+
describe('Verify CreateLoopModal', () => {
it('Test the render method', async () => {
diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js b/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js
index b7ab8a5..5fff586 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Loop/DeployLoopModal.js
@@ -1,8 +1,8 @@
/*-
* ============LICENSE_START=======================================================
- * ONAP CLAMP
+ * ONAP POLICY-CLAMP
* ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
* reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,6 +44,7 @@ const FormStyled = styled(Form.Group)`
`
export default class DeployLoopModal extends React.Component {
+
constructor(props, context) {
super(props, context);
@@ -65,13 +66,7 @@ export default class DeployLoopModal extends React.Component {
getInitialKeyValue(temporaryPropertiesJson) {
const deployJsonList = temporaryPropertiesJson["dcaeDeployParameters"];
- let initialKey;
- Object.keys(deployJsonList)
- .filter((obj) => Object.keys(deployJsonList).indexOf(obj) === 0)
- .map(obj =>
- initialKey = obj
- );
- return initialKey;
+ return Object.keys(deployJsonList).find((obj) => Object.keys(deployJsonList).indexOf(obj) === 0);
}
componentWillReceiveProps(newProps) {
@@ -145,8 +140,8 @@ export default class DeployLoopModal extends React.Component {
const deployJsonList = this.state.temporaryPropertiesJson["dcaeDeployParameters"];
var indents = [];
- Object.keys(deployJsonList).map((item, key) =>
- indents.push(<Tab eventKey={ item } title={ item }>
+ Object.keys(deployJsonList).forEach(item =>
+ indents.push(<Tab key={ item } eventKey={ item } title={ item }>
{ this.renderDeployParam(deployJsonList[item]) }
</Tab>)
);
@@ -155,8 +150,8 @@ export default class DeployLoopModal extends React.Component {
renderDeployParam(deployJson) {
var indents = [];
- Object.keys(deployJson).map((item, key) =>
- indents.push(<FormStyled>
+ Object.keys(deployJson).forEach(item =>
+ indents.push(<FormStyled key={ item }>
<Form.Label>{ item }</Form.Label>
<Form.Control type="text" name={ item } onChange={ this.handleChange } defaultValue={ deployJson[item] }></Form.Control>
</FormStyled>));
diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js b/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js
index 8f8b74d..0d20341 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Loop/ModifyLoopModal.js
@@ -130,13 +130,6 @@ export default class ModifyLoopModal extends React.Component {
this.initializeToscaPolicyModelsInfo();
}
- componentWillReceiveProps(newProps) {
- this.setState({
- loopCache: newProps.loopCache,
- temporaryPropertiesJson: JSON.parse(JSON.stringify(newProps.loopCache.getGlobalProperties()))
- });
- }
-
initializeToscaPolicyModelsInfo() {
var operationalPolicies = this.state.loopCache.getOperationalPolicies();
var selectedPolicyModels = [];
diff --git a/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap
index 4779ced..33f8faa 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap
+++ b/gui-clamp/ui-react/src/components/dialogs/Loop/__snapshots__/DeployLoopModal.test.js.snap
@@ -26,9 +26,12 @@ exports[`Verify DeployLoopModal Test the render method 1`] = `
>
<Tab
eventKey="testMs"
+ key="testMs"
title="testMs"
>
- <Styled(FormGroup)>
+ <Styled(FormGroup)
+ key="location_id"
+ >
<FormLabel
column={false}
srOnly={false}
@@ -42,7 +45,9 @@ exports[`Verify DeployLoopModal Test the render method 1`] = `
type="text"
/>
</Styled(FormGroup)>
- <Styled(FormGroup)>
+ <Styled(FormGroup)
+ key="policy_id"
+ >
<FormLabel
column={false}
srOnly={false}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PoliciesTreeViewer.js
new file mode 100644
index 0000000..5bca4e6
--- /dev/null
+++ b/gui-clamp/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>
+ );
+ }
+}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js
new file mode 100644
index 0000000..de29947
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyDeploymentEditor.js
@@ -0,0 +1,178 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+import React, { forwardRef } from 'react';
+import Modal from 'react-bootstrap/Modal';
+import styled from 'styled-components';
+import Button from 'react-bootstrap/Button';
+import Alert from 'react-bootstrap/Alert';
+import PolicyService from '../../../api/PolicyService';
+import FormGroup from '@material-ui/core/FormGroup';
+import Checkbox from '@material-ui/core/Checkbox';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+
+const DivWhiteSpaceStyled = styled.div`
+ white-space: pre;
+`
+
+const PanelDiv = styled.div`
+ text-align: justify;
+ font-size: ${ props => props.theme.policyEditorFontSize };
+ background-color: ${ props => props.theme.loopViewerBackgroundColor };
+`
+
+export default class PolicyDeploymentEditor extends React.Component {
+
+ state = {
+ policyData: this.props.policyData,
+ showSuccessAlert: false,
+ showFailAlert: false,
+ checkboxesState: this.createPdpStructure(this.props.policyData),
+ checkboxesInitialState: this.createPdpStructure(this.props.policyData),
+ };
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.handleUpdatePdpDeployment = this.handleUpdatePdpDeployment.bind(this);
+ this.disableAlert = this.disableAlert.bind(this);
+ this.renderPdpDeploymentCheckboxes = this.renderPdpDeploymentCheckboxes.bind(this);
+ this.createPdpStructure = this.createPdpStructure.bind(this);
+ this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
+ this.createPdpGroupOperations = this.createPdpGroupOperations.bind(this);
+ }
+
+ handleClose() {
+ this.setState({ show: false });
+
+ }
+
+ disableAlert() {
+ this.setState({ showSuccessAlert: false, showFailAlert: false });
+ }
+
+ createPdpGroupOperations(initialStates, newStates) {
+ let commandsArray = [];
+ initialStates.forEach(initElem => {
+ let newStateFound = newStates.find(newElement => newElement.name === initElem.name);
+ if (initElem.value !== newStateFound.value) {
+ let newPdpGroupsArray = newStateFound.name.split("/");
+ let operation = "POST/";
+ if (initElem.value) {
+ operation = "DELETE/";
+ }
+ commandsArray.push(operation + newPdpGroupsArray[0] + "/" + newPdpGroupsArray[1] + "/"
+ + this.state.policyData.name + "/" + this.state.policyData.version);
+ }
+ });
+ return commandsArray.length > 0 ? { "PdpActions": commandsArray } : undefined;
+ }
+
+ handleUpdatePdpDeployment() {
+ let operationsList = this.createPdpGroupOperations(this.state.checkboxesInitialState,
+ this.state.checkboxesState);
+ if (typeof (operationsList) !== "undefined") {
+ PolicyService.updatePdpDeployment(operationsList).then(respPdpDeploymentUpdate => {
+ if (typeof (respPdpDeploymentUpdate) === "undefined") {
+ //it indicates a failure
+ this.setState({
+ showFailAlert: true,
+ showMessage: 'Pdp Deployment update Failure'
+ });
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Pdp Deployment Update successful'
+ });
+ this.props.policiesTableUpdateFunction();
+ }
+ })
+ } else {
+ this.setState({
+ showSuccessAlert: true,
+ showMessage: 'Pdp Deployment: Nothing to change'
+ });
+ }
+ }
+
+ createPdpStructure(policyData) {
+ // Create map with data for all group/subgroup where the policy is deployed
+ let infoPdpMap = new Map();
+ if (typeof policyData.pdpGroupInfo !== "undefined") {
+ policyData["pdpGroupInfo"].forEach(pdpGroupElem => {
+ let pdpGroupName = Object.keys(pdpGroupElem)[0];
+ pdpGroupElem[pdpGroupName]["pdpSubgroups"].forEach(pdpSubGroupElem => {
+ infoPdpMap.set(pdpGroupName + "/" + pdpSubGroupElem["pdpType"], true);
+ });
+ });
+ }
+ // Create the possible values for pdpgroup/subgroup and tick the ones where policy is deployed
+ let pdpStates = [];
+ if (typeof policyData.supportedPdpGroups !== "undefined") {
+ for (const pdpGroup of policyData["supportedPdpGroups"]) {
+ let pdpGroupName = Object.keys(pdpGroup)[0];
+ for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
+ let fullName = pdpGroupName + "/" + pdpSubGroup;
+ pdpStates.push({
+ name: fullName,
+ value: infoPdpMap.get(fullName) !== undefined
+ });
+ }
+ }
+ }
+ return pdpStates;
+ }
+
+ handleCheckboxChange(event) {
+ const checkboxesArray = this.state.checkboxesState;
+ checkboxesArray.find(element => element.name === event.target.name).value = event.target.checked;
+ this.setState({ checkboxesState: checkboxesArray });
+ }
+
+ renderPdpDeploymentCheckboxes() {
+ return this.state.checkboxesState.map(item => {
+ return <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>
+ );
+ }
+}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js
index 525d66b..1e27541 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.js
@@ -31,9 +31,7 @@ import TextField from '@material-ui/core/TextField';
import Alert from 'react-bootstrap/Alert';
import PolicyService from '../../../api/PolicyService';
import OnapUtils from '../../../utils/OnapUtils';
-import uuid from 'react-uuid';
-//const JSONEditor = require("@json-editor/json-editor").JSONEditor;
const DivWhiteSpaceStyled = styled.div`
white-space: pre;
`
@@ -46,7 +44,6 @@ const JsonEditorDiv = styled.div`
border: 1px solid #C0C0C0;
`
const PanelDiv = styled.div`
- margin-top: 20px;
text-align: justify;
font-size: ${ props => props.theme.policyEditorFontSize };
background-color: ${ props => props.theme.loopViewerBackgroundColor };
@@ -63,7 +60,7 @@ export default class PolicyEditor extends React.Component {
showSuccessAlert: false,
showFailAlert: false,
jsonEditor: null,
- jsonEditorDivId: uuid(),
+ jsonEditorDivId: this.props.policyModelType + "_" + this.props.policyModelTypeVersion + "_" + this.props.policyName + "_" + this.props.policyVersion,
}
constructor(props, context) {
@@ -112,17 +109,12 @@ export default class PolicyEditor extends React.Component {
showSuccessAlert: true,
showMessage: 'Policy ' + this.state.policyName + '/' + this.state.policyVersion + ' created successfully'
});
- this.props.policyUpdateFunction();
+ this.props.policiesTableUpdateFunction();
}
})
}
}
- bumpVersion(versionToBump) {
- let semVer = versionToBump.split(".");
- return parseInt(semVer[0]) + 1 + "." + semVer[1] + "." + semVer[2];
- }
-
getToscaModelForPolicy() {
PolicyToscaService.getToscaPolicyModel(this.state.policyModelType, this.state.policyModelTypeVersion).then(respJsonPolicyTosca => {
if (respJsonPolicyTosca !== {}) {
@@ -139,27 +131,10 @@ export default class PolicyEditor extends React.Component {
}
createJsonEditor(toscaModel, editorData) {
- /*JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
- getTab: function(text,tabId) {
- var liel = document.createElement('li');
- liel.classList.add('nav-item');
- var ael = document.createElement("a");
- ael.classList.add("nav-link");
- ael.setAttribute("style",'padding:10px;max-width:160px;');
- ael.setAttribute("href", "#" + tabId);
- ael.setAttribute('data-toggle', 'tab');
- text.setAttribute("style",'word-wrap:break-word;');
- ael.appendChild(text);
- liel.appendChild(ael);
- return liel;
- }
- });*/
-
return new JSONEditor(document.getElementById(this.state.jsonEditorDivId),
{
schema: toscaModel,
startval: editorData,
- //theme: 'myBootstrap4',
theme: 'bootstrap4',
iconlib: 'fontawesome5',
object_layout: 'grid',
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js
new file mode 100644
index 0000000..111f2c6
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyEditor.test.js
@@ -0,0 +1,72 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import PolicyEditor from './PolicyEditor';
+import { shallow, mount } from 'enzyme';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+
+describe('Verify PolicyEditor', () => {
+ const fs = require('fs');
+
+ let toscaJson = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.json', { encoding: 'utf8', flag: 'r' })
+
+ const policyProperties = {
+ "tca.policy": {
+ "domain": "measurementsForVfScaling",
+ "metricsPerEventName": [
+ {
+ "policyScope": "DCAE",
+ "thresholds": [
+ {
+ "version": "1.0.2",
+ "severity": "MAJOR",
+ "thresholdValue": 200,
+ "closedLoopEventStatus": "ONSET",
+ "closedLoopControlName": "LOOP_test",
+ "direction": "LESS_OR_EQUAL",
+ "fieldPath": "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta"
+ }
+ ],
+ "eventName": "vLoadBalancer",
+ "policyVersion": "v0.0.1",
+ "controlLoopSchemaType": "VM",
+ "policyName": "DCAE.Config_tca-hi-lo"
+ }
+ ]
+ }
+ };
+
+
+ it('Test the render method', async () => {
+ PolicyToscaService.getToscaPolicyModel = jest.fn().mockImplementation(() => {
+ return Promise.resolve(toscaJson);
+ });
+
+ const component = mount(<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();
+ });
+});
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js
index 105b2c5..0c7637c 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.js
@@ -137,21 +137,6 @@ export default class PolicyModal extends React.Component {
}
createJsonEditor(toscaModel, editorData) {
- /*JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({
- getTab: function(text,tabId) {
- var liel = document.createElement('li');
- liel.classList.add('nav-item');
- var ael = document.createElement("a");
- ael.classList.add("nav-link");
- ael.setAttribute("style",'padding:10px;max-width:160px;');
- ael.setAttribute("href", "#" + tabId);
- ael.setAttribute('data-toggle', 'tab');
- text.setAttribute("style",'word-wrap:break-word;');
- ael.appendChild(text);
- liel.appendChild(ael);
- return liel;
- }
- });*/
return new JSONEditor(document.getElementById("editor"),
{
schema: toscaModel,
@@ -316,17 +301,17 @@ export default class PolicyModal extends React.Component {
}
renderButton() {
- var allElement = [(<Button variant="secondary" onClick={ this.handleClose }>
+ 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 variant="primary" disabled={ this.readOnly } onClick={ this.handleSave }>
+ <Button key="save" variant="primary" disabled={ this.readOnly } onClick={ this.handleSave }>
Save Changes
</Button>
));
allElement.push((
- <Button variant="primary" disabled={ this.readOnly } onClick={ this.handleRefresh }>
+ <Button key="refresh" variant="primary" disabled={ this.readOnly } onClick={ this.handleRefresh }>
Refresh
</Button>
));
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js
index 734f22e..658b19e 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyModal.test.js
@@ -1,8 +1,8 @@
/*-
* ============LICENSE_START=======================================================
- * ONAP CLAMP
+ * ONAP POLICY-CLAMP
* ================================================================================
- * Copyright (C) 2020 AT&T Intellectual Property. All rights
+ * Copyright (C) 2020-2021 AT&T Intellectual Property. All rights
* reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,6 +26,7 @@ import PolicyModal from './PolicyModal';
import LoopCache from '../../../api/LoopCache';
import LoopService from '../../../api/LoopService';
import OnapConstant from '../../../utils/OnapConstants';
+import { shallow } from 'enzyme';
describe('Verify PolicyModal', () => {
beforeEach(() => {
@@ -52,6 +53,7 @@ describe('Verify PolicyModal', () => {
"jsonRepresentation": { "schema": {} }
}]
};
+
const loopCache = new LoopCache(loopCacheStr);
const historyMock = { push: jest.fn() };
const flushPromises = () => new Promise(setImmediate);
@@ -125,4 +127,9 @@ describe('Verify PolicyModal', () => {
instance.handlePdpSubgroupChange(event);
expect(component.state('chosenPdpSubgroup')).toEqual("option1");
});
+
+ it('Test the render method', () => {
+ const component = shallow(<PolicyModal loopCache={ loopCache } match={ match }/>)
+ expect(component).toMatchSnapshot();
+ });
});
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js
new file mode 100644
index 0000000..8093b7e
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/PolicyToscaFileSelector.js
@@ -0,0 +1,133 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+
+import React from 'react'
+import Modal from 'react-bootstrap/Modal';
+import Form from 'react-bootstrap/Form';
+import Row from 'react-bootstrap/Row';
+import Col from 'react-bootstrap/Col';
+import styled from 'styled-components';
+import Alert from 'react-bootstrap/Alert';
+import { Input, InputLabel, Button, SvgIcon } from "@material-ui/core";
+import PublishIcon from '@material-ui/icons/Publish';
+import PolicyService from '../../../api/PolicyService';
+
+const ModalStyled = styled(Modal)`
+ background-color: transparent;
+`
+
+const StyledMessagesDiv = styled.div`
+ overflow: auto;
+ max-height: 300px;
+`
+
+
+export default class PolicyToscaFileSelector extends React.Component {
+
+ state = {
+ show: this.props.show,
+ alertMessages: [],
+ }
+
+ constructor(props, context) {
+ super(props, context);
+ this.handleClose = this.handleClose.bind(this);
+ this.onFileChange = this.onFileChange.bind(this);
+ }
+
+ componentDidUpdate(prevProps) {
+ if (this.props.show !== this.state.show) {
+ this.setState({ show: this.props.show });
+ }
+ }
+
+ handleClose() {
+ this.props.disableFunction();
+ this.setState({ alertMessages: [] });
+ }
+
+ onFileChange(target) {
+ this.setState({ alertMessages: [] });
+ target.currentTarget.files.forEach(file => {
+ const fileReader = new FileReader();
+ fileReader.readAsDataURL(file);
+ fileReader.onload = (content) => {
+ PolicyService.sendNewPolicyModel(atob(content.target.result.split(",")[1])).then(respModelCreate => {
+ if (typeof (respModelCreate) === "undefined") {
+ //it indicates a failure
+ this.setState(state => {
+ return {
+ alertMessages: [...state.alertMessages, (<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>
+ );
+ }
+}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js
index ce4edce..fc69a63 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.js
@@ -26,8 +26,7 @@ import PolicyToscaService from '../../../api/PolicyToscaService';
import styled from 'styled-components';
import Button from 'react-bootstrap/Button';
-const JsonEditorDiv = styled.div`
- margin-top: 20px;
+const ToscaDiv = styled.div`
background-color: ${ props => props.theme.toscaTextareaBackgroundColor };
text-align: justify;
font-size: ${ props => props.theme.toscaTextareaFontSize };
@@ -57,11 +56,11 @@ export default class ToscaViewer extends React.Component {
render() {
return (
- <JsonEditorDiv>
+ <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>
- </JsonEditorDiv>
+ </ToscaDiv>
);
}
}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js
new file mode 100644
index 0000000..5b59760
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ToscaViewer.test.js
@@ -0,0 +1,54 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP POLICY-CLAMP
+ * ================================================================================
+ * Copyright (C) 2021 AT&T Intellectual Property. All rights
+ * reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END============================================
+ * ===================================================================
+ *
+ */
+import React from 'react';
+import ToscaViewer from './ToscaViewer';
+import { shallow, mount } from 'enzyme';
+import PolicyToscaService from '../../../api/PolicyToscaService';
+
+describe('Verify ToscaViewer', () => {
+ const fs = require('fs');
+
+ let toscaYaml = fs.readFileSync('src/components/dialogs/Policy/toscaData.test.yaml', { encoding: 'utf8', flag: 'r' })
+
+ const toscaData = {
+ "policyModelType": "onap.policies.controlloop.Guard",
+ "version": "1.0.0",
+ "policyAcronym": "Guard",
+ "createdDate": "2021-04-09T02:29:31.407356Z",
+ "updatedDate": "2021-04-09T02:29:31.407356Z",
+ "updatedBy": "Not found",
+ "createdBy": "Not found",
+ "tableData": {
+ "id": 0
+ }
+ };
+
+ it('Test the render method', async () => {
+ PolicyToscaService.getToscaPolicyModelYaml = jest.fn().mockImplementation(() => {
+ return Promise.resolve(toscaYaml);
+ });
+ const component = shallow(<ToscaViewer toscaData={ toscaData }/>);
+ await PolicyToscaService.getToscaPolicyModelYaml();
+ expect(component).toMatchSnapshot();
+ });
+});
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js b/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
index a97deea..f571bc1 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
@@ -43,24 +43,27 @@ import ViewColumn from '@material-ui/icons/ViewColumn';
import DehazeIcon from '@material-ui/icons/Dehaze';
import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos';
import AddIcon from '@material-ui/icons/Add';
-import FormControlLabel from '@material-ui/core/FormControlLabel';
+import PublishIcon from '@material-ui/icons/Publish';
import Switch from '@material-ui/core/Switch';
import MaterialTable from "material-table";
import PolicyService from '../../../api/PolicyService';
import PolicyToscaService from '../../../api/PolicyToscaService';
-import Select from 'react-select';
+import Select from '@material-ui/core/Select';
import Alert from 'react-bootstrap/Alert';
import Tabs from 'react-bootstrap/Tabs';
import Tab from 'react-bootstrap/Tab';
import PolicyEditor from './PolicyEditor';
import ToscaViewer from './ToscaViewer';
+import PolicyDeploymentEditor from './PolicyDeploymentEditor';
+import PoliciesTreeViewer from './PoliciesTreeViewer';
+import PolicyToscaFileSelector from './PolicyToscaFileSelector';
const DivWhiteSpaceStyled = styled.div`
white-space: pre;
`
const ModalStyled = styled(Modal)`
- @media (min-width: 1000px) {
+ @media (min-width: 800px) {
.modal-xl {
max-width: 96%;
}
@@ -73,26 +76,38 @@ const DetailedRow = styled.div`
font-size: ${ props => props.theme.policyEditorFontSize };
width: 97%;
margin-left: auto;
- margin-right: 0;
+ margin-right: auto;
+ margin-top: 20px;
`
+const PoliciesTreeViewerDiv = styled.div`
+ width: 20%;
+ float: left;
+ left: 0;
+ overflow: auto;
+`
+
+const MaterialTableDiv = styled.div`
+ float: right;
+ width: 80%;
+ left: 20%;
+`
const standardCellStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' };
-const cellPdpGroupStyle = { backgroundColor: '#039be5', color: '#FFF', border: '1px solid black' };
const headerStyle = { backgroundColor: '#ddd', border: '2px solid black' };
const rowHeaderStyle = { backgroundColor: '#ddd', fontSize: '15pt', text: 'bold', border: '1px solid black' };
export default class ViewAllPolicies extends React.Component {
state = {
show: true,
- content: 'Please select a policy to display it',
- selectedRowId: -1,
policiesListData: [],
+ policiesListDataFiltered: [],
toscaModelsListData: [],
+ toscaModelsListDataFiltered: [],
jsonEditorForPolicy: new Map(),
- prefixGrouping: false,
showSuccessAlert: false,
showFailAlert: false,
+ showFileSelector: false,
policyColumnsDefinition: [
{
title: "Policy Name", field: "name",
@@ -102,7 +117,7 @@ export default class ViewAllPolicies extends React.Component {
{
title: "Policy Version", field: "version",
cellStyle: standardCellStyle,
- headerStyle: headerStyle
+ headerStyle: headerStyle,
},
{
title: "Policy Type", field: "type",
@@ -115,20 +130,13 @@ export default class ViewAllPolicies extends React.Component {
headerStyle: headerStyle
},
{
- title: "Deployed in PDP", field: "pdpGroupInfo.pdpGroup",
- cellStyle: cellPdpGroupStyle,
- headerStyle: headerStyle,
- render: rowData => this.renderPdpGroupDropBox(rowData),
- grouping: false
- },
- {
- title: "PDP Group", field: "pdpGroupInfo.pdpGroup",
- cellStyle: cellPdpGroupStyle,
+ title: "Deployable in PDP Group", field: "supportedPdpGroupsString",
+ cellStyle: standardCellStyle,
headerStyle: headerStyle
},
{
- title: "PDP SubGroup", field: "pdpGroupInfo.pdpSubGroup",
- cellStyle: cellPdpGroupStyle,
+ title: "Deployed in PDP Group", field: "pdpGroupInfoString",
+ cellStyle: standardCellStyle,
headerStyle: headerStyle
}
],
@@ -183,62 +191,63 @@ export default class ViewAllPolicies extends React.Component {
constructor(props, context) {
super(props, context);
this.handleClose = this.handleClose.bind(this);
- this.renderPdpGroupDropBox = this.renderPdpGroupDropBox.bind(this);
- this.handlePdpGroupChange = this.handlePdpGroupChange.bind(this);
- this.handlePrefixGrouping = this.handlePrefixGrouping.bind(this);
this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
this.disableAlert = this.disableAlert.bind(this);
this.getAllPolicies = this.getAllPolicies.bind(this);
this.getAllToscaModels = this.getAllToscaModels.bind(this);
+ this.generateAdditionalPolicyColumns = this.generateAdditionalPolicyColumns.bind(this);
+ this.filterPolicies = this.filterPolicies.bind(this);
+ this.filterTosca = this.filterTosca.bind(this);
+ this.showFileSelector = this.showFileSelector.bind(this);
+ this.disableFileSelector = this.disableFileSelector.bind(this);
this.getAllPolicies();
this.getAllToscaModels();
}
- getAllToscaModels() {
- PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => {
- this.setState({ toscaModelsListData: toscaModelsList });
- });
- }
-
- handlePdpGroupChange(e) {
- let pdpSplit = e.value.split("/");
- let selectedPdpGroup = pdpSplit[0];
- let selectedSubPdpGroup = pdpSplit[1];
- if (typeof selectedSubPdpGroup !== "undefined") {
- let temp = this.state.policiesListData;
- temp[this.state.selectedRowId]["pdpGroupInfo"] = { "pdpGroup": selectedPdpGroup, "pdpSubGroup": selectedSubPdpGroup };
- this.setState({ policiesListData: temp });
- } else {
- delete this.state.policiesListData[this.state.selectedRowId]["pdpGroupInfo"];
- }
- }
+ generateAdditionalPolicyColumns(policiesData) {
+ policiesData.forEach(policy => {
+ let supportedPdpGroupsString = "";
+ if (typeof policy.supportedPdpGroups !== "undefined") {
+ for (const pdpGroup of policy["supportedPdpGroups"]) {
+ for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
+ supportedPdpGroupsString += (Object.keys(pdpGroup)[0] + "/" + pdpSubGroup + "\r\n");
+ }
+ }
+ policy["supportedPdpGroupsString"] = supportedPdpGroupsString;
+ }
- renderPdpGroupDropBox(dataRow) {
- let optionItems = [{ label: "NOT DEPLOYED", value: "NOT DEPLOYED" }];
- let selectedItem = { label: "NOT DEPLOYED", value: "NOT DEPLOYED" };
- if (typeof dataRow.supportedPdpGroups !== "undefined") {
- for (const pdpGroup of dataRow["supportedPdpGroups"]) {
- for (const pdpSubGroup of Object.values(pdpGroup)[0]) {
- optionItems.push({
- label: Object.keys(pdpGroup)[0] + "/" + pdpSubGroup,
- value: Object.keys(pdpGroup)[0] + "/" + pdpSubGroup
+ let infoPdpGroup = "";
+ if (typeof policy.pdpGroupInfo !== "undefined") {
+ policy["pdpGroupInfo"].forEach(pdpGroupElem => {
+ let groupName = Object.keys(pdpGroupElem)[0];
+ pdpGroupElem[groupName]["pdpSubgroups"].forEach(pdpSubGroupElem => {
+ infoPdpGroup += (groupName + "/" + pdpSubGroupElem["pdpType"] + " ("
+ + pdpGroupElem[groupName]["pdpGroupState"] + ")" + "\r\n");
});
- }
+ policy["pdpGroupInfoString"] = infoPdpGroup;
+ });
}
- }
- if (typeof dataRow.pdpGroupInfo !== "undefined") {
- selectedItem = {
- label: dataRow["pdpGroupInfo"]["pdpGroup"] + "/" + dataRow["pdpGroupInfo"]["pdpSubGroup"],
- value: dataRow["pdpGroupInfo"]["pdpGroup"] + "/" + dataRow["pdpGroupInfo"]["pdpSubGroup"]
- };
- }
- return (<div style={ { width: '250px' } }><Select value={ selectedItem } options={ optionItems } onChange={ this.handlePdpGroupChange }/></div>);
+ });
+ }
+
+ getAllToscaModels() {
+ PolicyToscaService.getToscaPolicyModels().then(toscaModelsList => {
+ this.setState({
+ toscaModelsListData: toscaModelsList,
+ toscaModelsListDataFiltered: toscaModelsList
+ });
+ });
}
getAllPolicies() {
PolicyService.getPoliciesList().then(allPolicies => {
- this.setState({ policiesListData: allPolicies["policies"] })
+ this.generateAdditionalPolicyColumns(allPolicies["policies"])
+ this.setState({
+ policiesListData: allPolicies["policies"],
+ policiesListDataFiltered: allPolicies["policies"],
+ })
});
+
}
handleClose() {
@@ -246,10 +255,6 @@ export default class ViewAllPolicies extends React.Component {
this.props.history.push('/')
}
- handlePrefixGrouping(event) {
- this.setState({ prefixGrouping: event.target.checked });
- }
-
handleDeletePolicy(event, rowData) {
PolicyService.deletePolicy(rowData["type"], rowData["type_version"], rowData["name"], rowData["version"]).then(
respPolicyDeletion => {
@@ -264,8 +269,8 @@ export default class ViewAllPolicies extends React.Component {
showSuccessAlert: true,
showMessage: 'Policy successfully Deleted'
});
+ this.getAllPolicies();
}
- this.getAllPolicies();
}
)
}
@@ -274,62 +279,92 @@ export default class ViewAllPolicies extends React.Component {
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>
- <FormControlLabel
- control={ <Switch checked={ this.state.prefixGrouping } onChange={ this.handlePrefixGrouping }/> }
- label="Group by prefix"
- />
- <MaterialTable
- title={ "Policies" }
- data={ this.state.policiesListData }
- columns={ this.state.policyColumnsDefinition }
- icons={ this.state.tableIcons }
- onRowClick={ (event, rowData, togglePanel) => togglePanel() }
- options={ {
- grouping: true,
- exportButton: true,
- headerStyle: rowHeaderStyle,
- rowStyle: rowData => ({
- backgroundColor: (this.state.selectedRowId !== -1 && this.state.selectedRowId === rowData.tableData.id) ? '#EEE' : '#FFF'
- }),
- 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"] } policyUpdateFunction={ this.getAllPolicies }/>
- </DetailedRow>
- )
- },
- },
- {
- icon: DehazeIcon,
- tooltip: 'Show Raw Data',
- render: rowData => {
- return (
- <DetailedRow>
- <pre>{ JSON.stringify(rowData, null, 2) }</pre>
- </DetailedRow>
- )
- },
- },
- ] }
- actions={ [
- {
- icon: forwardRef((props, ref) => <DeleteRoundedIcon { ...props } ref={ ref }/>),
- tooltip: 'Delete Policy',
- onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
- }
- ] }
- />
+ <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>
);
@@ -339,61 +374,71 @@ export default class ViewAllPolicies extends React.Component {
return (
<Tab eventKey="tosca models" title="Tosca Models in Policy Framework">
<Modal.Body>
- <FormControlLabel
- control={ <Switch checked={ this.state.prefixGrouping } onChange={ this.handlePrefixGrouping }/> }
- label="Group by prefix"
- />
- <MaterialTable
- title={ "Tosca Models" }
- data={ this.state.toscaModelsListData }
- columns={ this.state.toscaColumnsDefinition }
- icons={ this.state.tableIcons }
- onRowClick={ (event, rowData, togglePanel) => togglePanel() }
- options={ {
- grouping: true,
- exportButton: true,
- headerStyle: rowHeaderStyle,
- rowStyle: rowData => ({
- backgroundColor: (this.state.selectedRowId !== -1 && this.state.selectedRowId === rowData.tableData.id) ? '#EEE' : '#FFF'
- }),
- actionsColumnIndex: -1
- } }
- detailPanel={ [
- {
- icon: ArrowForwardIosIcon,
- tooltip: 'Show Tosca',
- render: rowData => {
- return (
- <DetailedRow>
- <ToscaViewer toscaData={ rowData }/>
- </DetailedRow>
- )
- },
- },
- {
- icon: DehazeIcon,
- tooltip: 'Show Raw Data',
- render: rowData => {
- return (
- <DetailedRow>
- <pre>{ JSON.stringify(rowData, null, 2) }</pre>
- </DetailedRow>
- )
- },
- },
- {
- icon: AddIcon,
- tooltip: 'Create a policy from this model',
- render: rowData => {
- return (
- <DetailedRow>
- <PolicyEditor policyModelType={ rowData["policyModelType"] } policyModelTypeVersion={ rowData["version"] } policyProperties={ {} } policyUpdateFunction={ this.getAllPolicies }/>
- </DetailedRow>
- )
- },
- },
- ] }
- />
+ <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>
);
@@ -401,27 +446,30 @@ export default class ViewAllPolicies extends React.Component {
render() {
return (
- <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>
+ <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>
);
}
}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyEditor.test.js.snap
new file mode 100644
index 0000000..bf84e91
--- /dev/null
+++ b/gui-clamp/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 eVKaeY"
+ >
+ <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 hXXDCR"
+ 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/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap
new file mode 100644
index 0000000..8b1261b
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/PolicyModal.test.js.snap
@@ -0,0 +1,159 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify PolicyModal Test the render method 1`] = `
+<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/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap
new file mode 100644
index 0000000..61fb485
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/__snapshots__/ToscaViewer.test.js.snap
@@ -0,0 +1,30 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Verify ToscaViewer Test the render method 1`] = `
+<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/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json
new file mode 100644
index 0000000..3b001b3
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.json
@@ -0,0 +1,179 @@
+{
+ "title": "onap.policies.monitoring.tcagen2",
+ "type": "object",
+ "required": [
+ "tca.policy"
+ ],
+ "properties": {
+ "tca.policy": {
+ "title": "onap.datatypes.monitoring.tca_policy",
+ "type": "object",
+ "required": [
+ "domain",
+ "metricsPerEventName"
+ ],
+ "properties": {
+ "domain": {
+ "type": "string",
+ "description": "Domain name to which TCA needs to be applied",
+ "default": "measurementsForVfScaling",
+ "const": "measurementsForVfScaling"
+ },
+ "metricsPerEventName": {
+ "type": "array",
+ "description": "Contains eventName and threshold details that need to be applied to given eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.metricsPerEventName",
+ "type": "object",
+ "required": [
+ "controlLoopSchemaType",
+ "eventName",
+ "policyName",
+ "policyScope",
+ "policyVersion",
+ "thresholds"
+ ],
+ "properties": {
+ "controlLoopSchemaType": {
+ "type": "string",
+ "description": "Specifies Control Loop Schema Type for the event Name e.g. VNF, VM",
+ "enum": [
+ "VM",
+ "VNF"
+ ]
+ },
+ "eventName": {
+ "type": "string",
+ "description": "Event name to which thresholds need to be applied"
+ },
+ "policyName": {
+ "type": "string",
+ "description": "TCA Policy Scope Name"
+ },
+ "policyScope": {
+ "type": "string",
+ "description": "TCA Policy Scope"
+ },
+ "policyVersion": {
+ "type": "string",
+ "description": "TCA Policy Scope Version"
+ },
+ "thresholds": {
+ "type": "array",
+ "description": "Thresholds associated with eventName",
+ "items": {
+ "title": "onap.datatypes.monitoring.thresholds",
+ "type": "object",
+ "required": [
+ "closedLoopControlName",
+ "closedLoopEventStatus",
+ "direction",
+ "fieldPath",
+ "severity",
+ "thresholdValue",
+ "version"
+ ],
+ "properties": {
+ "closedLoopControlName": {
+ "type": "string",
+ "description": "Closed Loop Control Name associated with the threshold"
+ },
+ "closedLoopEventStatus": {
+ "type": "string",
+ "description": "Closed Loop Event Status of the threshold",
+ "enum": [
+ "ONSET",
+ "ABATED"
+ ]
+ },
+ "direction": {
+ "type": "string",
+ "description": "Direction of the threshold",
+ "enum": [
+ "LESS",
+ "LESS_OR_EQUAL",
+ "GREATER",
+ "GREATER_OR_EQUAL",
+ "EQUAL"
+ ]
+ },
+ "fieldPath": {
+ "type": "string",
+ "description": "Json field Path as per CEF message which needs to be analyzed for TCA",
+ "enum": [
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].receivedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsDelta",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedTotalPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedOctetsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedUnicastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedMulticastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedBroadcastPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedDiscardedPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.vNicPerformanceArray[*].transmittedErrorPacketsAccumulated",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuIdle",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageInterrupt",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageNice",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSoftIrq",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSteal",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuUsageSystem",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].cpuWait",
+ "$.event.measurementsForVfScalingFields.cpuUsageArray[*].percentUsage",
+ "$.event.measurementsForVfScalingFields.meanRequestLatency",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryBuffered",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryCached",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryConfigured",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryFree",
+ "$.event.measurementsForVfScalingFields.memoryUsageArray[*].memoryUsed",
+ "$.event.measurementsForVfScalingFields.additionalMeasurements[*].arrayOfFields[0].value"
+ ]
+ },
+ "severity": {
+ "type": "string",
+ "description": "Threshold Event Severity",
+ "enum": [
+ "CRITICAL",
+ "MAJOR",
+ "MINOR",
+ "WARNING",
+ "NORMAL"
+ ]
+ },
+ "thresholdValue": {
+ "type": "integer",
+ "description": "Threshold value for the field Path inside CEF message"
+ },
+ "version": {
+ "type": "string",
+ "description": "Version number associated with the threshold"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ },
+ "format": "tabs-top"
+ }
+ }
+ }
+ }
+}
diff --git a/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml
new file mode 100644
index 0000000..15a3cec
--- /dev/null
+++ b/gui-clamp/ui-react/src/components/dialogs/Policy/toscaData.test.yaml
@@ -0,0 +1,13 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+policy_types:
+ onap.policies.controlloop.Guard:
+ properties: {
+ }
+ name: onap.policies.controlloop.Guard
+ version: 1.0.0
+ derived_from: tosca.policies.Root
+ metadata: {
+ }
+ description: Guard Policies for Control Loop Operational Policies
+name: ToscaServiceTemplateSimple
+version: 1.0.0
diff --git a/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js b/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js
index 7257337..e7be984 100644
--- a/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js
+++ b/gui-clamp/ui-react/src/components/dialogs/Tosca/ViewLoopTemplatesModal.js
@@ -1,8 +1,8 @@
/*-
* ============LICENSE_START=======================================================
- * ONAP CLAMP
+ * ONAP POLICY-CLAMP
* ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights
+ * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights
* reserved.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js b/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js
index e58c61a..d452f6d 100644
--- a/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js
+++ b/gui-clamp/ui-react/src/components/dialogs/UserInfoModal.js
@@ -60,7 +60,7 @@ export default class UserInfoModal extends React.Component {
renderPermissions() {
if (this.state.userInfo["allPermissions"]) {
var listOfPermissions = this.state.userInfo["allPermissions"].map(function (perm) {
- return <Form.Control plaintext readOnly defaultValue={ perm }/>;
+ return <Form.Control key={ perm } plaintext readOnly defaultValue={ perm }/>;
})
return listOfPermissions;
} else {
diff --git a/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap
index 7c725bc..548a2d9 100644
--- a/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap
+++ b/gui-clamp/ui-react/src/components/dialogs/__snapshots__/UserInfoModal.test.js.snap
@@ -91,11 +91,13 @@ exports[`Verify UserInfoModal Test the render method full permission 1`] = `
<Col>
<FormControl
defaultValue="permission1"
+ key="permission1"
plaintext={true}
readOnly={true}
/>
<FormControl
defaultValue="permission2"
+ key="permission2"
plaintext={true}
readOnly={true}
/>
diff --git a/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js b/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js
index b03b740..3435ba3 100644
--- a/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js
+++ b/gui-clamp/ui-react/src/components/loop_viewer/logs/LoopLogs.js
@@ -67,10 +67,9 @@ export default class LoopLogs extends React.Component {
}
renderLogs() {
- if (this.state.loopCache.getLoopLogsArray() != null) {
- return (
- this.state.loopCache.getLoopLogsArray().map(row => <TableRow logRow={ row }/>)
- )
+ let logsArray = this.state.loopCache.getLoopLogsArray();
+ if (logsArray != null) {
+ return (logsArray.map(row => <TableRow key={ row.id } logRow={ row }/>));
}
}
diff --git a/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap b/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap
index 75b817b..996c674 100644
--- a/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap
+++ b/gui-clamp/ui-react/src/components/loop_viewer/logs/__snapshots__/LoopLogs.test.js.snap
@@ -45,6 +45,7 @@ exports[`Verify LoopLogs Test the render method 1`] = `
</thead>
<tbody>
<TableRow
+ key="1"
logRow={
Object {
"id": 1,
diff --git a/gui-clamp/ui-react/src/components/loop_viewer/status/LoopStatus.js b/gui-clamp/ui-react/src/components/loop_viewer/status/LoopStatus.js
index 2994c84..f539ad4 100644
--- a/gui-clamp/ui-react/src/components/loop_viewer/status/LoopStatus.js
+++ b/gui-clamp/ui-react/src/components/loop_viewer/status/LoopStatus.js
@@ -57,12 +57,13 @@ export default class LoopStatus extends React.Component {
renderStatus() {
- if (this.state.loopCache.getComponentStates() != null) {
- return Object.keys(this.state.loopCache.getComponentStates()).map((key) => {
+ let componentStates = this.state.loopCache.getComponentStates();
+ if (componentStates != null) {
+ return Object.keys(componentStates).map((key) => {
console.debug("Adding status for: ", key);
var res = {}
res[key] = this.state.loopCache.getComponentStates()[key];
- return (<TableRow statusRow={ {
+ return (<TableRow key={ key } statusRow={ {
'componentName': key,
'stateName': this.state.loopCache.getComponentStates()[key].componentState.stateName,
'description': this.state.loopCache.getComponentStates()[key].componentState.description
diff --git a/gui-clamp/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap b/gui-clamp/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap
index 73da5ff..24d879d 100644
--- a/gui-clamp/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap
+++ b/gui-clamp/ui-react/src/components/loop_viewer/status/__snapshots__/LoopStatus.test.js.snap
@@ -40,6 +40,7 @@ exports[`Verify LoopStatus Test the render method 1`] = `
</thead>
<tbody>
<TableRow
+ key="POLICY"
statusRow={
Object {
"componentName": "POLICY",
@@ -49,6 +50,7 @@ exports[`Verify LoopStatus Test the render method 1`] = `
}
/>
<TableRow
+ key="DCAE"
statusRow={
Object {
"componentName": "DCAE",
diff --git a/gui-clamp/ui-react/src/components/loop_viewer/svg/SvgGenerator.js b/gui-clamp/ui-react/src/components/loop_viewer/svg/SvgGenerator.js
index f5f5047..2692aef 100644
--- a/gui-clamp/ui-react/src/components/loop_viewer/svg/SvgGenerator.js
+++ b/gui-clamp/ui-react/src/components/loop_viewer/svg/SvgGenerator.js
@@ -27,220 +27,222 @@ import LoopCache from '../../../api/LoopCache';
import OnapConstant from '../../../utils/OnapConstants';
const DivStyled = styled.div`
- overflow-x: scroll;
- display: flex;
- width: 100%;
- height: 100%;
+ overflow-x: scroll;
+ display: flex;
+ width: 100%;
+ height: 100%;
`
-const emptySvg = (<svg> <text x="60" y="40">No LOOP (SVG)</text> </svg>);
+const emptySvg = (<svg>
+ <text x="60" y="40">No LOOP (SVG)</text>
+</svg>);
class SvgGenerator extends React.Component {
- boxWidth = 200;
- boxHeight = 100;
- boxSpace = 50;
-
- static GENERATED_FROM_INSTANCE = "INSTANCE";
- static GENERATED_FROM_TEMPLATE = "TEMPLATE";
-
- state = {
- loopCache: new LoopCache({}),
- clickable: false,
- generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE
- }
-
- constructor(props) {
- super(props);
- this.state.loopCache = props.loopCache;
- this.state.clickable = props.clickable;
- this.state.generatedFrom = props.generatedFrom;
- this.handleSvgClick = this.handleSvgClick.bind(this);
- this.renderSvg = this.renderSvg.bind(this);
- }
-
- shouldComponentUpdate(nextProps, nextState) {
- return this.state.loopCache !== nextState.loopCache;
- }
-
- componentWillReceiveProps(newProps) {
- if (this.state.loopCache !== newProps.loopCache) {
- this.setState({
- loopCache: newProps.loopCache,
- });
- }
- }
-
- handleSvgClick(event) {
- console.debug("svg click event received");
- if (this.state.clickable) {
- var elementName = event.target.parentNode.getAttribute('policyId');
- console.info("SVG element clicked", elementName);
- // Only allow movement to policy editing IF there busyLoadingCOunt is 0,
- // meaning we are not waiting for refreshStatus to complete, for example
- if (elementName !== null && !this.props.isBusyLoading()) {
- this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName);
- }
- }
- }
-
- createVesBox (xPos) {
- return this.createOneBox(xPos,null,null,'VES Collector','VES',null);
+ boxWidth = 200;
+ boxHeight = 100;
+ boxSpace = 50;
+
+ static GENERATED_FROM_INSTANCE = "INSTANCE";
+ static GENERATED_FROM_TEMPLATE = "TEMPLATE";
+
+ state = {
+ loopCache: new LoopCache({}),
+ clickable: false,
+ generatedFrom: SvgGenerator.GENERATED_FROM_INSTANCE, // INSTANCE / TEMPLATE
+ }
+
+ constructor(props) {
+ super(props);
+ this.state.loopCache = props.loopCache;
+ this.state.clickable = props.clickable;
+ this.state.generatedFrom = props.generatedFrom;
+ this.handleSvgClick = this.handleSvgClick.bind(this);
+ this.renderSvg = this.renderSvg.bind(this);
+ }
+
+ shouldComponentUpdate(nextProps, nextState) {
+ return this.state.loopCache !== nextProps.loopCache;
+ }
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.loopCache !== this.props.loopCache) {
+ this.setState({
+ loopCache: this.props.loopCache,
+ });
}
-
- createOneArrow(xPos) {
- return (
- <svg width={this.boxSpace} height={this.boxHeight} x={xPos}>
- <defs>
- <marker viewBox="0 0 20 20" markerWidth="20" markerHeight="20" orient="auto" refX="8.5" refY="5" id="arrow">
- <path d="m 1 5 l 0 -3 l 7 3 l -7 3 z"
- stroke-width= "1" stroke-linecap= "butt" stroke-dasharray= "10000, 1"
- fill="#000000" stroke="#000000" />
- </marker>
- </defs>
- <line x1="0" y1="50%" x2="100%" y2="50%" stroke-width="2" color="black" stroke="black" marker-end="url(#arrow)"/>
- </svg>
- );
- }
-
- createBeginCircle(xPos, text) {
- return (
- <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
- <circle cx={this.boxWidth-30} cy="50%" r="30" stroke-width="1" color="black" stroke="black" fill="#27ae60"/>
- <text x={this.boxWidth-30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
- </svg>
- );
+ }
+
+ handleSvgClick(event) {
+ console.debug("svg click event received");
+ if (this.state.clickable) {
+ var elementName = event.target.parentNode.getAttribute('policyId');
+ console.info("SVG element clicked", elementName);
+ // Only allow movement to policy editing IF there busyLoadingCOunt is 0,
+ // meaning we are not waiting for refreshStatus to complete, for example
+ if (elementName !== null && !this.props.isBusyLoading()) {
+ this.props.history.push("/policyModal/" + event.target.parentNode.getAttribute('policyType') + "/" + elementName);
+ }
}
-
- createEndCircle(xPos, text) {
- return (
- <svg width={this.boxWidth} height={this.boxHeight} x={xPos}>
- <circle cx={30} cy="50%" r="30" stroke-width="2" color="black" stroke="black" fill="#27ae60"/>
- <text x={30} y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs" >{text}</text>
- </svg>
- );
+ }
+
+ createVesBox(xPos) {
+ return this.createOneBox(xPos, null, null, 'VES Collector', 'VES', null);
+ }
+
+ createOneArrow(xPos) {
+ return (
+ <svg width={ this.boxSpace } height={ this.boxHeight } x={ xPos }>
+ <defs>
+ <marker viewBox="0 0 20 20" markerWidth="20" markerHeight="20" orient="auto" refX="8.5" refY="5" id="arrow">
+ <path d="m 1 5 l 0 -3 l 7 3 l -7 3 z"
+ stroke-width="1" stroke-linecap="butt" stroke-dasharray="10000, 1"
+ fill="#000000" stroke="#000000"/>
+ </marker>
+ </defs>
+ <line x1="0" y1="50%" x2="100%" y2="50%" stroke-width="2" color="black" stroke="black" marker-end="url(#arrow)"/>
+ </svg>
+ );
+ }
+
+ createBeginCircle(xPos, text) {
+ return (
+ <svg width={ this.boxWidth } height={ this.boxHeight } x={ xPos }>
+ <circle cx={ this.boxWidth - 30 } cy="50%" r="30" stroke-width="1" color="black" stroke="black" fill="#27ae60"/>
+ <text x={ this.boxWidth - 30 } y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs">{ text }</text>
+ </svg>
+ );
+ }
+
+ createEndCircle(xPos, text) {
+ return (
+ <svg width={ this.boxWidth } height={ this.boxHeight } x={ xPos }>
+ <circle cx={ 30 } cy="50%" r="30" stroke-width="2" color="black" stroke="black" fill="#27ae60"/>
+ <text x={ 30 } y="50%" text-anchor="middle" dominant-baseline="middle" textLength="20%" lengthAdjust="spacingAndGlyphs">{ text }</text>
+ </svg>
+ );
+ }
+
+ createOneBox(xPos, policyId, loopElementModelId, name, title, policyType) {
+ return (
+ <svg width={ this.boxWidth } height={ this.boxHeight } x={ xPos } title="test">
+ <g policyId={ policyId } loopElementModelId={ loopElementModelId } policyType={ policyType }>
+ <rect width="100%" height="100%" stroke-width="2" color="black" stroke="black" fill="#1abc9c"/>
+ <text x="50%" y="15%" color="white" fill="white" dominant-baseline="middle" text-anchor="middle" textLength="50%" lengthAdjust="spacingAndGlyphs">{ title }</text>
+ <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" textLength="80%" lengthAdjust="spacingAndGlyphs">{ name }</text>
+ <text x="50%" y="80%" text-anchor="middle" dominant-baseline="middle" textLength="110%" lengthAdjust="spacingAndGlyphs">{ policyId }</text>
+ </g>
+ </svg>
+ );
+ }
+
+ createSvgFromTemplate() {
+ const allElements = [];
+ var xPos = 0;
+
+ allElements.push(this.createBeginCircle(xPos, "Start"))
+ xPos += (this.boxWidth + this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
+
+ allElements.push(this.createVesBox(xPos));
+ xPos += (this.boxWidth + this.boxSpace);
+
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
+ //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType)
+ for (var loopElement of this.state.loopCache.getAllLoopElementModels()) {
+
+ allElements.push(this.createOneBox(xPos,
+ loopElement['name'],
+ loopElement['name'],
+ loopElement['shortName'],
+ loopElement['loopElementType'],
+ loopElement['loopElementType']))
+ xPos += (this.boxWidth + this.boxSpace);
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
}
- createOneBox(xPos, policyId, loopElementModelId , name, title, policyType) {
- return (
- <svg width={this.boxWidth} height={this.boxHeight} x={xPos} title="test">
- <g policyId={policyId} loopElementModelId={loopElementModelId} policyType={policyType}>
- <rect width="100%" height="100%" stroke-width="2" color="black" stroke="black" fill="#1abc9c"/>
- <text x="50%" y="15%" color="white" fill="white" dominant-baseline="middle" text-anchor="middle" textLength="50%" lengthAdjust="spacingAndGlyphs">{title}</text>
- <text x="50%" y="50%" text-anchor="middle" dominant-baseline="middle" textLength="80%" lengthAdjust="spacingAndGlyphs" >{name}</text>
- <text x="50%" y="80%" text-anchor="middle" dominant-baseline="middle" textLength="110%" lengthAdjust="spacingAndGlyphs" >{policyId}</text>
- </g>
- </svg>
- );
- }
+ allElements.push(this.createEndCircle(xPos, "End"))
+ xPos += (this.boxWidth + this.boxSpace);
- createSvgFromTemplate() {
- const allElements = [];
- var xPos = 0;
+ return allElements;
+ }
- allElements.push(this.createBeginCircle(xPos,"Start"))
- xPos+=(this.boxWidth+this.boxSpace);
+ createSvgFromInstance() {
+ const allElements = [];
+ var xPos = 0;
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
+ allElements.push(this.createBeginCircle(xPos, "Start"))
+ xPos += (this.boxWidth + this.boxSpace);
- allElements.push(this.createVesBox(xPos));
- xPos+=(this.boxWidth+this.boxSpace);
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
- //createOneBox(xPos, policyId, loopElementModelId , name, title, policyType)
- for (var loopElement of this.state.loopCache.getAllLoopElementModels()) {
+ allElements.push(this.createVesBox(xPos));
+ xPos += (this.boxWidth + this.boxSpace);
- allElements.push(this.createOneBox(xPos,
- loopElement['name'],
- loopElement['name'],
- loopElement['shortName'],
- loopElement['loopElementType'],
- loopElement['loopElementType']))
- xPos+=(this.boxWidth+this.boxSpace);
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
- }
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
- allElements.push(this.createEndCircle(xPos, "End"))
- xPos+=(this.boxWidth+this.boxSpace);
-
- return allElements;
+ for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) {
+ var loopElementModelName = this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel'];
+ if (loopElementModelName !== undefined) {
+ loopElementModelName = loopElementModelName['name'];
+ }
+ allElements.push(this.createOneBox(xPos,
+ this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'],
+ loopElementModelName,
+ this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'],
+ 'microservice',
+ OnapConstant.microServiceType))
+ xPos += (this.boxWidth + this.boxSpace);
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
}
- createSvgFromInstance() {
- const allElements = [];
- var xPos = 0;
-
- allElements.push(this.createBeginCircle(xPos,"Start"))
- xPos+=(this.boxWidth+this.boxSpace);
-
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
-
- allElements.push(this.createVesBox(xPos));
- xPos+=(this.boxWidth+this.boxSpace);
-
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
-
- for (var msPolicy in this.state.loopCache.getMicroServicePolicies()) {
- var loopElementModelName = this.state.loopCache.getMicroServicePolicies()[msPolicy]['loopElementModel'];
- if (loopElementModelName !== undefined) {
- loopElementModelName = loopElementModelName['name'];
- }
- allElements.push(this.createOneBox(xPos,
- this.state.loopCache.getMicroServicePolicies()[msPolicy]['name'],
- loopElementModelName,
- this.state.loopCache.getMicroServicePolicies()[msPolicy]['policyModel']['policyAcronym'],
- 'microservice',
- OnapConstant.microServiceType))
- xPos+=(this.boxWidth+this.boxSpace);
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
- }
-
- for (var opPolicy in this.state.loopCache.getOperationalPolicies()) {
- loopElementModelName = this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel'];
- if (loopElementModelName !== undefined) {
- loopElementModelName = loopElementModelName['name'];
- }
- allElements.push(this.createOneBox(xPos,
- this.state.loopCache.getOperationalPolicies()[opPolicy]['name'],
- loopElementModelName,
- this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'],
- 'operational',
- OnapConstant.operationalPolicyType))
- xPos+=(this.boxWidth+this.boxSpace);
- allElements.push(this.createOneArrow(xPos-this.boxSpace));
- }
-
- allElements.push(this.createEndCircle(xPos, "End"))
- xPos+=(this.boxWidth+this.boxSpace);
-
- return allElements;
+ for (var opPolicy in this.state.loopCache.getOperationalPolicies()) {
+ loopElementModelName = this.state.loopCache.getOperationalPolicies()[opPolicy]['loopElementModel'];
+ if (loopElementModelName !== undefined) {
+ loopElementModelName = loopElementModelName['name'];
+ }
+ allElements.push(this.createOneBox(xPos,
+ this.state.loopCache.getOperationalPolicies()[opPolicy]['name'],
+ loopElementModelName,
+ this.state.loopCache.getOperationalPolicies()[opPolicy]['policyModel']['policyAcronym'],
+ 'operational',
+ OnapConstant.operationalPolicyType))
+ xPos += (this.boxWidth + this.boxSpace);
+ allElements.push(this.createOneArrow(xPos - this.boxSpace));
}
- renderSvg() {
- if (this.state.loopCache.getLoopName() === undefined) {
- return [emptySvg];
- }
- if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) {
- return this.createSvgFromInstance();
- } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) {
- return this.createSvgFromTemplate();
- }
- }
+ allElements.push(this.createEndCircle(xPos, "End"))
+ xPos += (this.boxWidth + this.boxSpace);
+
+ return allElements;
+ }
- render() {
- var allTheElements = this.renderSvg();
- var svgWidth = this.boxWidth*allTheElements.length;
- var svgHeight = this.boxHeight+50;
- return (
-
- <DivStyled onClick={this.handleSvgClick} >
- <svg height={svgHeight} width={svgWidth} viewBox="0,0,{svgWidth},{svgHeight}" preserveAspectRatio="none">
- <svg x="-50" y="25">
- {allTheElements}
- </svg>
- </svg>
- </DivStyled>
- );
+ renderSvg() {
+ if (this.state.loopCache.getLoopName() === undefined) {
+ return [emptySvg];
}
+ if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_INSTANCE) {
+ return this.createSvgFromInstance();
+ } else if (this.state.generatedFrom === SvgGenerator.GENERATED_FROM_TEMPLATE) {
+ return this.createSvgFromTemplate();
+ }
+ }
+
+ render() {
+ var allTheElements = this.renderSvg();
+ var svgWidth = this.boxWidth * allTheElements.length;
+ var svgHeight = this.boxHeight + 50;
+ return (
+
+ <DivStyled onClick={ this.handleSvgClick }>
+ <svg key="main" height={ svgHeight } width={ svgWidth } viewBox="0,0,{svgWidth},{svgHeight}" preserveAspectRatio="none">
+ <svg key="content" x="-50" y="25">
+ { allTheElements }
+ </svg>
+ </svg>
+ </DivStyled>
+ );
+ }
}
export default withRouter(SvgGenerator);
diff --git a/gui-clamp/ui-react/src/setupTests.js b/gui-clamp/ui-react/src/setupTests.js
index f553583..30ce019 100644
--- a/gui-clamp/ui-react/src/setupTests.js
+++ b/gui-clamp/ui-react/src/setupTests.js
@@ -22,7 +22,7 @@
*/
import { configure } from 'enzyme';
-import Adapter from 'enzyme-adapter-react-17-updated';
+import Adapter from '@wojtekmaj/enzyme-adapter-react-17';
configure({ adapter: new Adapter() });
-global.fetch = require('jest-fetch-mock'); \ No newline at end of file
+global.fetch = require('jest-fetch-mock');