Added Common Parameter Form 73/122873/3
authorsaul.gill <saul.gill@est.tech>
Mon, 26 Jul 2021 16:33:24 +0000 (17:33 +0100)
committersaul.gill <saul.gill@est.tech>
Thu, 29 Jul 2021 08:45:44 +0000 (09:45 +0100)
Added save button for user edits
Added commission button to push up edits
Added service to retrieve common parameters

Issue-ID: POLICY-3439
Change-Id: Ia355f36bf263bb1385db363a267c53af86504905
Signed-off-by: saul.gill <saul.gill@est.tech>
gui-clamp/ui-react/src/api/ControlLoopService.js
gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.js
gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.test.js
gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/CommissioningModal.test.js.snap
gui-clamp/ui-react/src/components/menu/MenuBar.js
gui-clamp/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap

index 1f3cbed..5938bd2 100644 (file)
@@ -119,6 +119,22 @@ export default class ControlLoopService {
 
   }
 
+  static async getCommonProperties(name, version, windowLocationPathName) {
+    const params = {
+      name: name,
+      version: version,
+      common: "true"
+    }
+
+    const response = await fetch(windowLocationPathName +
+      '/restservices/clds/v2/toscaControlLoop/getCommonOrInstanceProperties' + '?' + (new URLSearchParams(params)));
+
+    this.checkResponseForError(response);
+
+    return response;
+
+  }
+
   static async getToscaServiceTemplateSchema(section, windowLocationPathName) {
 
     const params = {
index 6baa06c..ffe149a 100644 (file)
@@ -23,7 +23,7 @@ import React, { useEffect, useState } from "react";
 import styled from "styled-components";
 import { JSONEditor } from "@json-editor/json-editor";
 import ControlLoopService from "../../../api/ControlLoopService";
-import OnapConstant from "../../../utils/OnapConstants";
+import { Alert } from "react-bootstrap";
 
 const ModalStyled = styled(Modal)`
   @media (min-width: 800px) {
@@ -44,10 +44,26 @@ const StyledMessagesDiv = styled.div`
 
 const CommissioningModal = (props) => {
   const [windowLocationPathName, setWindowLocationPathName] = useState('');
+  const [fullToscaTemplate, setFullToscaTemplate] = useState({});
   const [toscaInitialValues, setToscaInitialValues] = useState({});
+  const [commonProperties, setCommonProperties] = useState({})
   const [toscaJsonSchema, setToscaJsonSchema] = useState({});
-  const [jsonEditor, setJsonEditor] = useState({});
+  const [jsonEditor, setJsonEditor] = useState(null);
   const [show, setShow] = useState(true);
+  const [alertMessages, setAlertMessages] = useState();
+  const name = 'ToscaServiceTemplateSimple';
+  const version = '1.0.0';
+  let editorTemp = null
+
+  useEffect(async () => {
+    const toscaTemplateResponse = await ControlLoopService.getToscaTemplate(name, version, windowLocationPathName)
+      .catch(error => error.message);
+    const toscaCommonProperties = await ControlLoopService.getCommonProperties(name, version, windowLocationPathName)
+      .catch(error => error.message);
+
+    await renderJsonEditor(toscaTemplateResponse, toscaCommonProperties)
+
+  }, []);
 
   const handleClose = () => {
     console.log('handleClose called');
@@ -55,43 +71,150 @@ const CommissioningModal = (props) => {
     props.history.push('/');
   }
 
-  const getToscaServiceTemplateHandler = async (toscaServiceTemplateResponse) => {
+  const handleSave = () => {
+    updateTemplate(jsonEditor.getValue())
+  }
 
-    if (!toscaServiceTemplateResponse.ok) {
-      const toscaData = await toscaServiceTemplateResponse;
-      setToscaInitialValues(toscaData);
-    } else {
-      const toscaData = await toscaServiceTemplateResponse.json();
-      setToscaInitialValues(toscaData);
-    }
+
+
+  const handleCommission = async () => {
+    setWindowLocationPathName(window.location.pathname);
+
+    await ControlLoopService.deleteToscaTemplate('ToscaServiceTemplateSimple', "1.0.0", windowLocationPathName)
+      .catch(error => error.message)
+
+    const recommissioningResponse = await ControlLoopService.uploadToscaFile(fullToscaTemplate, windowLocationPathName)
+      .catch(error => error.message)
+
+    await receiveResponseFromCommissioning(recommissioningResponse)
   }
 
-  const getToscaSchemaHandler = async (toscaSchemaResponse) => {
+  const receiveResponseFromCommissioning = async (response) => {
 
-    if (!toscaSchemaResponse.ok) {
-      const toscaSchemaData = await toscaSchemaResponse;
-      setToscaJsonSchema(toscaSchemaData);
-    } else {
-      const toscaSchemaData = await toscaSchemaResponse.json();
-      setToscaJsonSchema(toscaSchemaData);
+    if (await response.ok) {
+      setAlertMessages(<Alert variant="success">
+        <Alert.Heading>Commissioning Success</Alert.Heading>
+        <p>Altered Template was Successfully Uploaded</p>
+        <hr/>
+      </Alert>);
+    }
+    else {
+      setAlertMessages(<Alert variant="danger">
+        <Alert.Heading>Commissioning Failure</Alert.Heading>
+        <p>Updated Template Failed to Upload</p>
+        <p>Status code: { await response.status }: { response.statusText }</p>
+        <p>Response Text: { await response.text() }</p>
+        <hr/>
+      </Alert>);
     }
+  };
+
+  const renderJsonEditor = async (template, commonProps) => {
+
+    const fullTemplate = await template.json()
+
+    setFullToscaTemplate(fullTemplate)
+    const allNodeTemplates = fullTemplate.topology_template.node_templates
+    const shortenedNodeTemplatesObjectStartValues = {}
+    // Get the common properties to construct a schema
+    // Get valid start values at the same time
+    const commonNodeTemplatesJson = await commonProps.json().then(data => {
+      const nodeTemplatesArray = Object.entries(data)
+      const shortenedNodeTemplatesObject = {}
+      nodeTemplatesArray.forEach(([key, temp]) => {
+        const currentNodeTemplate = allNodeTemplates[key]
+        const propertiesObject = {
+          properties: temp.properties
+        }
+
+        shortenedNodeTemplatesObject[key] = propertiesObject
+
+        const propertiesStartValues = {}
+
+        // Get all the existing start values to populate the properties in the schema
+        Object.entries(propertiesObject.properties).forEach(([propKey, prop]) => {
+          propertiesStartValues[propKey] = currentNodeTemplate.properties[propKey]
+        })
+
+        shortenedNodeTemplatesObjectStartValues[key] = propertiesStartValues
+
+      })
+
+      setToscaInitialValues(shortenedNodeTemplatesObjectStartValues)
+      return shortenedNodeTemplatesObject;
+    })
+
+    const propertySchema = makeSchemaForCommonProperties(commonNodeTemplatesJson)
+    setToscaJsonSchema(propertySchema)
+
+    editorTemp = createJsonEditor(propertySchema, shortenedNodeTemplatesObjectStartValues);
+    setJsonEditor(editorTemp)
   }
 
-  useEffect(async () => {
-    setWindowLocationPathName(window.location.pathname);
+  const updateTemplate = (userAddedCommonPropValues) => {
+    const nodeTemplates = fullToscaTemplate.topology_template.node_templates
+    const commonPropertyDataEntries = Object.entries(userAddedCommonPropValues)
 
-    const toscaTemplateResponse = await ControlLoopService.getToscaControlLoopDefinitions(windowLocationPathName)
-      .catch(error => error.message);
+    // This replaces the values for properties in the full tosca template
+    // that will be sent up to the api with the entries the user provided.
+    commonPropertyDataEntries.forEach(([templateKey, values]) => {
+      Object.entries(values).forEach(([propKey, propVal]) => {
+        nodeTemplates[templateKey].properties[propKey] = propVal
+      })
+    })
+
+    fullToscaTemplate.topology_template.node_templates = nodeTemplates
+
+    setFullToscaTemplate(fullToscaTemplate)
+    alert('Changes saved. Commission When Ready...')
+  }
 
-    const toscaSchemaResponse = await ControlLoopService.getToscaServiceTemplateSchema('node_templates', windowLocationPathName);
+  const makeSchemaForCommonProperties = (commonProps) => {
+    const commonPropsArr = Object.entries(commonProps)
 
-    createJsonEditor(await toscaSchemaResponse.json(), await toscaTemplateResponse.json());
+    const newSchemaObject = {}
 
-    }, []);
+    newSchemaObject.title = "CommonProperties"
+    newSchemaObject.type = "object"
+    newSchemaObject.properties = {}
+
+    commonPropsArr.forEach(([templateKey, template]) => {
+
+      const propertiesObject = {}
+      Object.entries(template.properties).forEach(([propKey, prop]) => {
+
+        propertiesObject[propKey] = {
+          type: getType(prop.type)
+        }
+
+      })
+      newSchemaObject.properties[templateKey] = {
+        properties: propertiesObject
+      }
+    })
+
+    return newSchemaObject
+
+  }
+
+  const getType = (propertyType) => {
+    switch (propertyType)
+    {
+      case "string":
+        return "string"
+      case "integer":
+        return "integer"
+      case "list":
+        return "array"
+      case "object":
+        return "object"
+      default:
+        return "string"
+    }
+  }
 
-  // TODO Need to Hook this up to a new camel endpoint to get it working
   const createJsonEditor = (toscaModel, editorData) => {
-    JSONEditor.defaults.options.collapse = true;
+    JSONEditor.defaults.options.collapse = false;
 
     return new JSONEditor(document.getElementById("editor"),
       {
@@ -101,13 +224,13 @@ const CommissioningModal = (props) => {
         iconlib: 'fontawesome5',
         object_layout: 'normal',
         disable_properties: false,
-        disable_edit_json: false,
+        disable_edit_json: true,
         disable_array_reorder: true,
         disable_array_delete_last_row: true,
         disable_array_delete_all_rows: false,
         array_controls_top: true,
         keep_oneof_values: false,
-        collapsed: true,
+        collapsed: false,
         show_errors: 'always',
         display_required_only: false,
         show_opt_in: false,
@@ -123,7 +246,7 @@ const CommissioningModal = (props) => {
                  backdrop="static"
                  keyboard={ false }>
       <Modal.Header closeButton>
-        <Modal.Title>Edit Control Loop Parameters</Modal.Title>
+        <Modal.Title>Edit Common Properties</Modal.Title>
       </Modal.Header>
       <br/>
       <div style={ { padding: '5px 5px 0px 5px' } }>
@@ -131,9 +254,16 @@ const CommissioningModal = (props) => {
           <div id="editor"/>
         </Modal.Body>
       </div>
+      <StyledMessagesDiv>
+        { alertMessages }
+      </StyledMessagesDiv>
       <Modal.Footer>
-        <Button variant="primary"
-                >Submit</Button>
+        <Button
+          variant="primary"
+          onClick={ handleSave }
+        >Save</Button>
+        <Button variant="success"
+                onClick={ handleCommission }>Commission</Button>
         <Button variant="secondary"
                 onClick={ handleClose }>Close</Button>
       </Modal.Footer>
index f189c58..054450c 100644 (file)
@@ -37,9 +37,9 @@ describe('Verify ReadAndConvertYaml', () => {
     expect(toJson(tree)).toMatchSnapshot();
   });
 
-  it('should have two Button elements', () => {
+  it('should have three Button elements', () => {
     const container = shallow(<CommissioningModal/>)
-    expect(container.find('Button').length).toEqual(2);
+    expect(container.find('Button').length).toEqual(3);
   });
 
   it('handleClose called when bottom button clicked', () => {
index 78c8983..41c13de 100644 (file)
@@ -13,7 +13,7 @@ exports[`Verify ReadAndConvertYaml renders correctly 1`] = `
     closeLabel="Close"
   >
     <ModalTitle>
-      Edit Control Loop Parameters
+      Edit Common Properties
     </ModalTitle>
   </ModalHeader>
   <br />
@@ -30,13 +30,23 @@ exports[`Verify ReadAndConvertYaml renders correctly 1`] = `
       />
     </ModalBody>
   </div>
+  <styled.div />
   <ModalFooter>
     <Button
       active={false}
       disabled={false}
+      onClick={[Function]}
       variant="primary"
     >
-      Submit
+      Save
+    </Button>
+    <Button
+      active={false}
+      disabled={false}
+      onClick={[Function]}
+      variant="success"
+    >
+      Commission
     </Button>
     <Button
       active={false}
index 650196c..abe73c1 100644 (file)
@@ -121,7 +121,7 @@ export default class MenuBar extends React.Component {
           <NavDropdown.Header>Commissioning</NavDropdown.Header>
           <NavDropdown.Item as={ StyledLink } to="/readToscaTemplate">Manage Commissioned Tosca Template</NavDropdown.Item>
           <NavDropdown.Item as={ StyledLink } to="/uploadToscaFile">Upload Tosca to Commissioning</NavDropdown.Item>
-          <NavDropdown.Item as={ StyledLink } to="/getJsonSchema">Edit Control Loop Type Definitions</NavDropdown.Item>
+          <NavDropdown.Item as={ StyledLink } to="/getJsonSchema">Edit Control Loop Common Properties</NavDropdown.Item>
         </StyledNavDropdown>
         <StyledNavDropdown title="Help">
           <StyledNavLink href="https://wiki.onap.org/" target="_blank">Wiki</StyledNavLink>
index a1705ee..800e1dd 100644 (file)
@@ -1341,7 +1341,7 @@ exports[`Verify MenuBar Test the render method 1`] = `
       disabled={false}
       to="/getJsonSchema"
     >
-      Edit Control Loop Type Definitions
+      Edit Control Loop Common Properties
     </DropdownItem>
   </Styled(NavDropdown)>
   <Styled(NavDropdown)