Add code in UI to create new policy version

Add code to call the policy create backend endpoint + alert box to show status of the creation + Fix backend +

Issue-ID: POLICY-2928
Signed-off-by: sebdet <sebastien.determe@intl.att.com>
Change-Id: Ia8f2506ecc692ad68111ebe7a55a92579b951908
diff --git a/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java b/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java
index cf3c165..44b1111 100644
--- a/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java
+++ b/src/main/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMerger.java
@@ -105,9 +105,11 @@
     /**
      * This method removes the pdp States added for one policy.
      *
-     * @param policyJsonNode The policy node in Json
+     * @param policyJsonNode The policy node Json as String
+     * @return The Json with pdp group info removed
      */
     public static JsonObject removePdpStatesOnePolicy(JsonObject policyJsonNode) {
+        //JsonObject policyJson = JsonUtils.GSON.fromJson(policyJsonNode, JsonObject.class);
         // Simply remove the nodes we have added.
         policyJsonNode.remove(PdpGroupsAnalyzer.ASSIGNED_PDP_GROUPS_INFO);
         policyJsonNode.remove(PdpGroupsAnalyzer.SUPPORTED_PDP_GROUPS_INFO);
diff --git a/src/main/resources/clds/camel/rest/clamp-api-v2.xml b/src/main/resources/clds/camel/rest/clamp-api-v2.xml
index bcad3ea..f924a8a 100644
--- a/src/main/resources/clds/camel/rest/clamp-api-v2.xml
+++ b/src/main/resources/clds/camel/rest/clamp-api-v2.xml
@@ -803,6 +803,107 @@
                 </doTry>
             </route>
         </post>
+        <get uri="/v2/templates"
+             outType="org.onap.policy.clamp.loop.template.LoopTemplate"
+             produces="application/json">
+            <route>
+                <removeHeaders pattern="*"/>
+                <doTry>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Templates')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getAllLoopTemplates()"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+                    <doCatch>
+                        <exception>java.lang.Exception</exception>
+                        <handled>
+                            <constant>true</constant>
+                        </handled>
+                        <to
+                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+                        <log loggingLevel="ERROR"
+                             message="GET ALL templates request failed: ${exception.stacktrace}"/>
+                        <setHeader headerName="CamelHttpResponseCode">
+                            <constant>500</constant>
+                        </setHeader>
+                        <setBody>
+                            <simple>GET ALL templates FAILED</simple>
+                        </setBody>
+                    </doCatch>
+                </doTry>
+            </route>
+        </get>
+        <get uri="/v2/templates/{templateName}"
+             outType="org.onap.policy.clamp.loop.template.LoopTemplate"
+             produces="application/json">
+            <route>
+                <removeHeaders pattern="*"
+                               excludePattern="templateName"/>
+                <doTry>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET a Template by NAME')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplate(${header.templateName})"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+                    <doCatch>
+                        <exception>java.lang.Exception</exception>
+                        <handled>
+                            <constant>true</constant>
+                        </handled>
+                        <to
+                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+                        <log loggingLevel="ERROR"
+                             message="GET Template request failed for template: ${header.templateName},  ${exception.stacktrace}"/>
+                        <setHeader headerName="CamelHttpResponseCode">
+                            <constant>500</constant>
+                        </setHeader>
+                        <setBody>
+                            <simple>GET Template FAILED</simple>
+                        </setBody>
+                    </doCatch>
+                </doTry>
+            </route>
+        </get>
+        <get uri="/v2/templates/names" outType="java.lang.String[]"
+             produces="application/json">
+            <route>
+                <removeHeaders pattern="*"/>
+                <doTry>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Loop Template Names')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplateNames()"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+                    <doCatch>
+                        <exception>java.lang.Exception</exception>
+                        <handled>
+                            <constant>true</constant>
+                        </handled>
+                        <to
+                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+                        <log loggingLevel="ERROR"
+                             message="GET All Template names request failed for template:  ${exception.stacktrace}"/>
+                        <setHeader headerName="CamelHttpResponseCode">
+                            <constant>500</constant>
+                        </setHeader>
+                        <setBody>
+                            <simple>GET All Template names FAILED</simple>
+                        </setBody>
+                    </doCatch>
+                </doTry>
+            </route>
+        </get>
+
+        <!-- NON LOOP related endpoints -->
         <get uri="/v2/dictionary"
              outType="org.onap.policy.clamp.tosca.Dictionary" produces="application/json">
             <route>
@@ -1217,106 +1318,6 @@
             </route>
         </put>
 
-        <get uri="/v2/templates"
-             outType="org.onap.policy.clamp.loop.template.LoopTemplate"
-             produces="application/json">
-            <route>
-                <removeHeaders pattern="*"/>
-                <doTry>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Templates')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getAllLoopTemplates()"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
-                    <doCatch>
-                        <exception>java.lang.Exception</exception>
-                        <handled>
-                            <constant>true</constant>
-                        </handled>
-                        <to
-                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
-                        <log loggingLevel="ERROR"
-                             message="GET ALL templates request failed: ${exception.stacktrace}"/>
-                        <setHeader headerName="CamelHttpResponseCode">
-                            <constant>500</constant>
-                        </setHeader>
-                        <setBody>
-                            <simple>GET ALL templates FAILED</simple>
-                        </setBody>
-                    </doCatch>
-                </doTry>
-            </route>
-        </get>
-        <get uri="/v2/templates/{templateName}"
-             outType="org.onap.policy.clamp.loop.template.LoopTemplate"
-             produces="application/json">
-            <route>
-                <removeHeaders pattern="*"
-                               excludePattern="templateName"/>
-                <doTry>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET a Template by NAME')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplate(${header.templateName})"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
-                    <doCatch>
-                        <exception>java.lang.Exception</exception>
-                        <handled>
-                            <constant>true</constant>
-                        </handled>
-                        <to
-                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
-                        <log loggingLevel="ERROR"
-                             message="GET Template request failed for template: ${header.templateName},  ${exception.stacktrace}"/>
-                        <setHeader headerName="CamelHttpResponseCode">
-                            <constant>500</constant>
-                        </setHeader>
-                        <setBody>
-                            <simple>GET Template FAILED</simple>
-                        </setBody>
-                    </doCatch>
-                </doTry>
-            </route>
-        </get>
-        <get uri="/v2/templates/names" outType="java.lang.String[]"
-             produces="application/json">
-            <route>
-                <removeHeaders pattern="*"/>
-                <doTry>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET ALL Loop Template Names')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'template','','read')"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.loop.template.LoopTemplatesService?method=getLoopTemplateNames()"/>
-                    <to
-                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
-                    <doCatch>
-                        <exception>java.lang.Exception</exception>
-                        <handled>
-                            <constant>true</constant>
-                        </handled>
-                        <to
-                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
-                        <log loggingLevel="ERROR"
-                             message="GET All Template names request failed for template:  ${exception.stacktrace}"/>
-                        <setHeader headerName="CamelHttpResponseCode">
-                            <constant>500</constant>
-                        </setHeader>
-                        <setBody>
-                            <simple>GET All Template names FAILED</simple>
-                        </setBody>
-                    </doCatch>
-                </doTry>
-            </route>
-        </get>
-
         <!-- Policy Related endpoints, not related to LOOP  -->
         <get uri="/v2/policies" outType="com.google.gson.JsonObject" produces="application/json">
             <route>
@@ -1360,11 +1361,13 @@
                 </doTry>
             </route>
         </get>
-        <!-- Update an existing policy, therefore it removes it from pdp first, delete it and then recreate it -->
-        <!--  TO BE DONE -->
 
         <!-- Create a new policy -->
-        <post uri="/v2/policies/{policyModelName}/{policyModelVersion}" outType="com.google.gson.JsonObject" produces="application/json">
+        <post uri="/v2/policies/{policyModelName}/{policyModelVersion}"
+              type="com.google.gson.JsonElement"
+              consumes="application/json"
+              outType="com.google.gson.JsonObject"
+              produces="application/json">
             <route>
                 <removeHeaders pattern="*"
                                excludePattern="policyModelName|policyModelVersion"/>
@@ -1382,6 +1385,9 @@
                     <setBody>
                         <method ref="org.onap.policy.clamp.policy.pdpgroup.PoliciesPdpMerger"
                                 method="removePdpStatesOnePolicy(${body})"/>
+                     </setBody>
+                    <setBody>
+                        <simple>${body.toString()}</simple>
                     </setBody>
                     <to uri="direct:create-policy"/>
                     <to
diff --git a/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java b/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java
index adb7978..ac05d03 100644
--- a/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java
+++ b/src/test/java/org/onap/policy/clamp/policy/pdpgroup/PoliciesPdpMergerTest.java
@@ -103,9 +103,8 @@
 
     @Test
     public void testRemovePdpStatesOnePolicy() throws IOException {
-        JsonObject policiesList = PoliciesPdpMerger.removePdpStatesOnePolicy(JsonUtils.GSON
-                .fromJson(ResourceFileUtils.getResourceAsString("example/policy/single-policy-enriched.json"),
-                        JsonObject.class));
+        JsonObject policiesList = PoliciesPdpMerger.removePdpStatesOnePolicy(JsonUtils.GSON.fromJson(
+                ResourceFileUtils.getResourceAsString("example/policy/single-policy-enriched.json"), JsonObject.class));
 
         assertThat(policiesList.get(PdpGroupsAnalyzer.ASSIGNED_PDP_GROUPS_INFO)).isNull();
         assertThat(policiesList.get(PdpGroupsAnalyzer.SUPPORTED_PDP_GROUPS_INFO)).isNull();
diff --git a/ui-react/src/api/PolicyService.js b/ui-react/src/api/PolicyService.js
index fdbb5d5..16cc1f3 100644
--- a/ui-react/src/api/PolicyService.js
+++ b/ui-react/src/api/PolicyService.js
@@ -40,4 +40,27 @@
         return {};
       });
   }
+  static createNewPolicy(policyModelType, policyModelVersion, policyJson) {
+    return fetch(window.location.pathname + 'restservices/clds/v2/policies/' + policyModelType + '/' + policyModelVersion, {
+            method: 'POST',
+            credentials: 'same-origin',
+            headers: {
+                "Content-Type": "application/json"
+            },
+            body: JSON.stringify(policyJson)
+        })
+      .then(function (response) {
+        console.debug("createNewPolicy response received: ", response.status);
+        if (response.ok) {
+          return response.text;
+        } else {
+          console.error("createNewPolicy query failed");
+          return "";
+        }
+      })
+      .catch(function (error) {
+        console.error("createNewPolicy error received", error);
+        throw new Error(error)
+      });
+  }
 }
diff --git a/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js b/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
index a1cf9d5..dfebc51 100644
--- a/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
+++ b/ui-react/src/components/dialogs/Policy/ViewAllPolicies.js
@@ -47,6 +47,12 @@
 import PolicyToscaService from '../../../api/PolicyToscaService';
 import Select from 'react-select';
 import JSONEditor from '@json-editor/json-editor';
+import OnapUtils from '../../../utils/OnapUtils';
+import Alert from 'react-bootstrap/Alert';
+
+const DivWhiteSpaceStyled = styled.div`
+	white-space: pre;
+`
 
 const ModalStyled = styled(Modal)`
     @media (min-width: 1200px) {
@@ -76,9 +82,11 @@
   state = {
         show: true,
         content: 'Please select a policy to display it',
-        selectedRow: -1,
+        selectedRowId: -1,
         policiesListData: [],
         prefixGrouping: false,
+        showSuccessAlert: false,
+        showFailAlert: false,
         policyColumnsDefinition: [
             {
                 title: "Policy Name", field: "name",
@@ -148,7 +156,8 @@
         this.handlePrefixGrouping = this.handlePrefixGrouping.bind(this);
         this.handleDeletePolicy = this.handleDeletePolicy.bind(this);
         this.handleUpdatePolicy = this.handleUpdatePolicy.bind(this);
-        this.handleCreateNewVersion = this.handleCreateNewVersion(this);
+        this.handleCreateNewVersion = this.handleCreateNewVersion.bind(this);
+        this.disableAlert = this.disableAlert.bind(this);
         this.getAllPolicies();
 
     }
@@ -159,10 +168,10 @@
         let selectedSubPdpGroup = pdpSplit[1];
         if (typeof selectedSubPdpGroup !== "undefined") {
             let temp = this.state.policiesListData;
-            temp[this.state.selectedRow]["pdpGroupInfo"] = {"pdpGroup":selectedPdpGroup,"pdpSubGroup":selectedSubPdpGroup};
+            temp[this.state.selectedRowId]["pdpGroupInfo"] = {"pdpGroup":selectedPdpGroup,"pdpSubGroup":selectedSubPdpGroup};
             this.setState({policiesListData: temp});
         } else {
-            delete this.state.policiesListData[this.state.selectedRow]["pdpGroupInfo"];
+            delete this.state.policiesListData[this.state.selectedRowId]["pdpGroupInfo"];
         }
     }
 
@@ -237,9 +246,9 @@
     handleOnRowClick(rowData) {
         PolicyToscaService.getToscaPolicyModel(rowData["type"], rowData["type_version"]).then(respJsonPolicyTosca => {
             this.setState({
-                selectedRow: rowData.tableData.id,
-                selectedRowJsonSchema: respJsonPolicyTosca,
-                selectedRowPolicyProperties: rowData["properties"],
+                selectedRowId: rowData.tableData.id,
+                selectedRowIdJsonSchema: respJsonPolicyTosca,
+                selectedRowIdPolicyProperties: rowData["properties"],
                 jsonEditorForPolicy: this.createJsonEditor(respJsonPolicyTosca, rowData["properties"])
                 });
         });
@@ -253,8 +262,52 @@
         return null;
     }
 
-    handleCreateNewVersion(event,rowData) {
-        return null;
+    customValidation(editorData) {
+        // method for sub-classes to override with customized validation
+        return [];
+    }
+
+    handleCreateNewVersion() {
+        var editorData = this.state.jsonEditorForPolicy.getValue();
+        var errors = this.state.jsonEditorForPolicy.validate();
+        errors = errors.concat(this.customValidation(editorData));
+
+        if (errors.length !== 0) {
+            console.error("Errors detected during policy data validation ", errors);
+            this.setState({
+                showFailAlert: true,
+                showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors)
+            });
+            return;
+        } else {
+            console.info("NO validation errors found in policy data");
+            let newPolicy = JSON.parse(JSON.stringify(this.state.policiesListData[this.state.selectedRowId]));
+            newPolicy["properties"] = editorData;
+            let newVersion = this.bumpVersion(newPolicy["version"]);
+            newPolicy["version"] = newVersion;
+            newPolicy["metadata"]["policy-version"] = newVersion;
+            // Remove stuff added by UI
+            delete newPolicy["tableData"];
+            PolicyService.createNewPolicy(newPolicy["type"], newPolicy["type_version"], newPolicy).then(respPolicyCreation => {
+                if (respPolicyCreation === "") {
+                    //it indicates a failure
+                    this.setState({
+                        showFailAlert: true,
+                        showMessage: 'Policy Creation Failure'
+                    });
+                } else {
+                    this.setState({
+                        showSuccessAlert: true,
+                        showMessage: 'Policy in version ' + newVersion + ' created successfully'
+                    });
+                }
+            })
+        }
+    }
+
+    bumpVersion(versionToBump) {
+        let semVer = versionToBump.split(".");
+        return parseInt(semVer[0])+1 + "." + semVer[1] + "." + semVer[2];
     }
 
     handleUpdatePolicy() {
@@ -262,11 +315,16 @@
         this.props.history.push('/')
     }
 
+    disableAlert() {
+        this.setState ({ showSuccessAlert: false, showFailAlert: false });
+    }
+
     render() {
     return (
             <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false}>
                 <Modal.Header closeButton>
                 </Modal.Header>
+
                 <Modal.Body>
                   <FormControlLabel
                         control={<Switch checked={this.state.prefixGrouping} onChange={this.handlePrefixGrouping} />}
@@ -283,7 +341,7 @@
                           exportButton: true,
                           headerStyle:rowHeaderStyle,
                           rowStyle: rowData => ({
-                            backgroundColor: (this.state.selectedRow !== -1 && this.state.selectedRow === rowData.tableData.id) ? '#EEE' : '#FFF'
+                            backgroundColor: (this.state.selectedRowId !== -1 && this.state.selectedRowId === rowData.tableData.id) ? '#EEE' : '#FFF'
                           })
                       }}
                       actions={[
@@ -293,14 +351,25 @@
                             onClick: (event, rowData) => this.handleDeletePolicy(event, rowData)
                           }
                       ]}
-
                 />
                 <JsonEditorDiv>
                     <h5>Policy Properties Editor</h5>
                     <div id="policy-editor" title="Policy Properties"/>
-                    <Button variant="secondary" title="Create a new policy version from the defined parameters" onClick={this.handleCreateNewVersion}>Create New Version</Button>
-                    <Button variant="secondary" title="Update the current policy version, BE CAREFUL this will undeploy the policy from PDP, delete it and then recreate the policy" onClick={this.handleUpdatePolicy}>Update Current Version</Button>
+                    <Button variant="secondary" title="Create a new policy version from the defined parameters"
+                        onClick={this.handleCreateNewVersion}>Create New Version</Button>
+                    <Button variant="secondary" title="Update the current policy version, BE CAREFUL this will undeploy the policy from PDP, delete it and then recreate the policy"
+                        onClick={this.handleUpdatePolicy}>Update Current Version</Button>
                 </JsonEditorDiv>
+                <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.Body>
                 <Modal.Footer>
                     <Button variant="secondary" onClick={this.handleClose}>Close</Button>