From 3f99e6d9f007477fe6074f470048440d2b29c1ff Mon Sep 17 00:00:00 2001 From: "saul.gill" Date: Mon, 12 Jul 2021 17:10:10 +0100 Subject: Added Commissioning Template Editor Added a new modal to allow editing of the tosca template Json schema from the backend generates a for the user Added Decommissioning capability while viewing template Added service for decommissioning Issue-ID: POLICY-3439 Change-Id: Ic5bec9ea26aa8df468d36a893faa06f88d248dd5 Signed-off-by: saul.gill --- gui-clamp/ui-react/src/LoopUI.js | 2 + .../ui-react/src/__snapshots__/LoopUI.test.js.snap | 4 + .../src/__snapshots__/OnapClamp.test.js.snap | 4 + gui-clamp/ui-react/src/api/ControlLoopService.js | 53 +++++++- .../dialogs/ControlLoop/CommissioningModal.js | 144 +++++++++++++++++++++ .../dialogs/ControlLoop/CommissioningModal.test.js | 69 ++++++++++ .../dialogs/ControlLoop/DeleteToscaTemplate.js | 54 ++++++++ .../ControlLoop/DeleteToscaTemplate.test.js | 55 ++++++++ .../dialogs/ControlLoop/GetToscaTemplate.js | 2 +- .../dialogs/ControlLoop/GetToscaTemplate.test.js | 2 +- .../dialogs/ControlLoop/ReadAndConvertYaml.js | 43 +++++- .../__snapshots__/CommissioningModal.test.js.snap | 51 ++++++++ .../__snapshots__/DeleteToscaTemplate.test.js.snap | 20 +++ .../__snapshots__/GetToscaTemplate.test.js.snap | 2 +- .../__snapshots__/ReadAndConvertYaml.test.js.snap | 15 ++- gui-clamp/ui-react/src/components/menu/MenuBar.js | 3 +- .../menu/__snapshots__/MenuBar.test.js.snap | 67 +++++++++- 17 files changed, 574 insertions(+), 16 deletions(-) create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.test.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.test.js create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/CommissioningModal.test.js.snap create mode 100644 gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/DeleteToscaTemplate.test.js.snap (limited to 'gui-clamp/ui-react/src') diff --git a/gui-clamp/ui-react/src/LoopUI.js b/gui-clamp/ui-react/src/LoopUI.js index 109a0b3..83ba570 100644 --- a/gui-clamp/ui-react/src/LoopUI.js +++ b/gui-clamp/ui-react/src/LoopUI.js @@ -54,6 +54,7 @@ import { Link } from 'react-router-dom'; import ReadAndConvertYaml from "./components/dialogs/ControlLoop/ReadAndConvertYaml"; import MonitorInstantiation from "./components/dialogs/ControlLoop/MonitorInstantiation"; import GetLocalToscaFileForUpload from "./components/dialogs/ControlLoop/GetLocalToscaFileForUpload"; +import CommissioningModal from "./components/dialogs/ControlLoop/CommissioningModal"; import UploadToscaInstantiation from "./components/dialogs/ControlLoop/UploadToscaInstantiation"; const StyledMainDiv = styled.div` @@ -301,6 +302,7 @@ export default class LoopUI extends React.Component { () }/> () }/> + () }/> () }/> () }/> () }/> diff --git a/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap b/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap index 040fdaa..4529589 100644 --- a/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap +++ b/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap @@ -13,6 +13,10 @@ exports[`Verify LoopUI Test the render method 1`] = ` path="/uploadToscaFile" render={[Function]} /> + + { + const [windowLocationPathName, setWindowLocationPathName] = useState(''); + const [toscaInitialValues, setToscaInitialValues] = useState({}); + const [toscaJsonSchema, setToscaJsonSchema] = useState({}); + const [jsonEditor, setJsonEditor] = useState({}); + const [show, setShow] = useState(true); + + const handleClose = () => { + console.log('handleClose called'); + setShow(false); + props.history.push('/'); + } + + const getToscaServiceTemplateHandler = async (toscaServiceTemplateResponse) => { + + if (!toscaServiceTemplateResponse.ok) { + const toscaData = await toscaServiceTemplateResponse; + setToscaInitialValues(toscaData); + } else { + const toscaData = await toscaServiceTemplateResponse.json(); + setToscaInitialValues(toscaData); + } + } + + const getToscaSchemaHandler = async (toscaSchemaResponse) => { + + if (!toscaSchemaResponse.ok) { + const toscaSchemaData = await toscaSchemaResponse; + setToscaJsonSchema(toscaSchemaData); + } else { + const toscaSchemaData = await toscaSchemaResponse.json(); + setToscaJsonSchema(toscaSchemaData); + } + } + + useEffect(async () => { + setWindowLocationPathName(window.location.pathname); + + const toscaTemplateResponse = await ControlLoopService.getToscaControlLoopDefinitions(windowLocationPathName) + .catch(error => error.message); + + const toscaSchemaResponse = await ControlLoopService.getToscaServiceTemplateSchema('node_templates', windowLocationPathName); + + createJsonEditor(await toscaSchemaResponse.json(), await toscaTemplateResponse.json()); + + }, []); + + // TODO Need to Hook this up to a new camel endpoint to get it working + const createJsonEditor = (toscaModel, editorData) => { + JSONEditor.defaults.options.collapse = true; + + return new JSONEditor(document.getElementById("editor"), + { + schema: toscaModel, + startval: editorData, + theme: 'bootstrap4', + iconlib: 'fontawesome5', + object_layout: 'normal', + disable_properties: false, + disable_edit_json: false, + disable_array_reorder: true, + disable_array_delete_last_row: true, + disable_array_delete_all_rows: false, + array_controls_top: true, + keep_oneof_values: false, + collapsed: true, + show_errors: 'always', + display_required_only: false, + show_opt_in: false, + prompt_before_delete: true, + required_by_default: false, + }) + } + + return ( + + + Edit Control Loop Parameters + +
+
+ +
+ +
+ + + + + + ); +} + +export default CommissioningModal; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.test.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.test.js new file mode 100644 index 0000000..f189c58 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/CommissioningModal.test.js @@ -0,0 +1,69 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import { mount, shallow } from 'enzyme'; +import ReadAndConvertYaml from './ReadAndConvertYaml'; +import toJson from "enzyme-to-json"; +import { act } from "react-dom/test-utils"; +import { createMemoryHistory } from "history"; +import CommissioningModal from "./CommissioningModal"; + +describe('Verify ReadAndConvertYaml', () => { + + it("renders without crashing", () => { + shallow(); + }); + + it("renders correctly", () => { + const tree = shallow(); + expect(toJson(tree)).toMatchSnapshot(); + }); + + it('should have two Button elements', () => { + const container = shallow() + expect(container.find('Button').length).toEqual(2); + }); + + it('handleClose called when bottom button clicked', () => { + const history = createMemoryHistory(); + const component = mount() + const logSpy = jest.spyOn(console, 'log'); + + + act(() => { + component.find('[variant="secondary"]').simulate('click'); + expect(logSpy).toHaveBeenCalledWith('handleClose called'); + }); + }); + + it('handleClose called when top-right button clicked', () => { + const history = createMemoryHistory(); + const component = mount() + const logSpy = jest.spyOn(console, 'log'); + + + act(() => { + component.find('[size="xl"]').get(0).props.onHide(); + expect(logSpy).toHaveBeenCalledWith('handleClose called'); + }); + }); + +}); diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.js new file mode 100644 index 0000000..c641272 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.js @@ -0,0 +1,54 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import React, { useState } from "react"; +import Button from "react-bootstrap/Button"; +import ControlLoopService from "../../../api/ControlLoopService"; + +const DeleteToscaTemplate = props => { + + const [windowLocationPathName, setWindowLocationPathname] = useState(''); + + const deleteTemplateHandler = async () => { + console.log('deleteTemplateHandler called'); + setWindowLocationPathname(window.location.pathname); + + const response = await ControlLoopService.deleteToscaTemplate(props.templateName, props.templateVersion, windowLocationPathName) + .catch(error => error.message); + + console.log('Response is ok: ' + response.ok); + + props.onDeleteToscaServiceTemplate(response); + + } + + return ( + + + + ); + + +} + +export default DeleteToscaTemplate; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.test.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.test.js new file mode 100644 index 0000000..e4d437a --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/DeleteToscaTemplate.test.js @@ -0,0 +1,55 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +import React from 'react'; +import { mount, shallow } from 'enzyme'; +import GetToscaTemplate from './GetToscaTemplate'; +import toJson from "enzyme-to-json"; +import DeleteToscaTemplate from "./DeleteToscaTemplate"; + +describe('Verify DeleteToscaTemplate', () => { + + it("renders without crashing", () => { + shallow(); + }); + + it("renders correctly", () => { + const tree = shallow(); + expect(toJson(tree)).toMatchSnapshot(); + }); + + it('should have a Button element', () => { + const container = shallow() + expect(container.find('Button').length).toEqual(1); + }); + + it('button should call deleteTemplateHandler when clicked', async () => { + const component = mount() + const logSpy = jest.spyOn(console, 'log'); + + component.find('[variant="danger"]').simulate('click'); + expect(logSpy).toHaveBeenCalledWith('deleteTemplateHandler called'); + }); + + it('should have a Button element with specified text', () => { + const container = shallow() + expect(container.find('Button').text()).toBe('Delete Tosca Service Template'); + }); +}); diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.js index 7da8c13..273957f 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.js @@ -40,7 +40,7 @@ const GetToscaTemplate = (props) => { + onClick={ getTemplateHandler }>Pull Tosca Service Template ); diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.test.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.test.js index ce2a398..38da005 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.test.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/GetToscaTemplate.test.js @@ -48,6 +48,6 @@ describe('Verify GetToscaTemplate', () => { it('should have a Button element with specified text', () => { const container = shallow() - expect(container.find('Button').text()).toBe('Get Tosca Service Template'); + expect(container.find('Button').text()).toBe('Pull Tosca Service Template'); }); }); diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ReadAndConvertYaml.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ReadAndConvertYaml.js index 53b541c..0ff8833 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ReadAndConvertYaml.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ReadAndConvertYaml.js @@ -24,6 +24,7 @@ import Button from "react-bootstrap/Button"; import { Alert } from "react-bootstrap"; import styled from 'styled-components'; +import DeleteToscaTemplate from "./DeleteToscaTemplate"; const ModalStyled = styled(Modal)` background-color: transparent; @@ -43,7 +44,9 @@ const PreStyled = styled.pre` const ReadAndConvertYaml = (props) => { const [show, setShow] = useState(true); const [toscaTemplateData, setToscaTemplateData] = useState(); - const [responeOk, setResponseOk] = useState(true); + const [deleteToscaTemplateData, setDeleteToscaTemplateData] = useState(); + const [responseOk, setResponseOk] = useState(true); + const [deleteResponseOk, setDeleteResponseOk] = useState(true); const name = 'ToscaServiceTemplateSimple'; const version = '1.0.0'; @@ -57,8 +60,9 @@ const ReadAndConvertYaml = (props) => { // console.log('getToscaServiceTemplateHandler called: ' + toscaServiceTemplate); if (!toscaServiceTemplateResponse.ok) { + console.log('Response is not ok'); setResponseOk(false); - const toscaData = await toscaServiceTemplateResponse; + const toscaData = await toscaServiceTemplateResponse.json(); setToscaTemplateData(toscaData); } else { setResponseOk(true); @@ -67,6 +71,20 @@ const ReadAndConvertYaml = (props) => { } } + const deleteToscaServiceTemplateHandler = async (deleteToscaServiceTemplateResponse) => { + + if (!deleteToscaServiceTemplateResponse.ok) { + console.log('Delete response not ok'); + setDeleteResponseOk(false); + const deleteToscaData = await deleteToscaServiceTemplateResponse; + setDeleteToscaTemplateData(deleteToscaData); + } else { + setDeleteResponseOk(true); + const deleteToscaData = await deleteToscaServiceTemplateResponse.json(); + setDeleteToscaTemplateData(deleteToscaData); + } + } + return ( { - { responeOk && { JSON.stringify(toscaTemplateData, null, 2) } } - { toscaTemplateData } + { responseOk && { JSON.stringify(toscaTemplateData, null, 2) } } + { JSON.stringify(toscaTemplateData, null, 2) } + { deleteResponseOk && responseOk && toscaTemplateData != null && + + } + { deleteToscaTemplateData } +

Delete Successful

{ JSON.stringify(deleteToscaTemplateData, null, 2) }
+ onClick={ handleClose }>Close ); -}; +} +; export default ReadAndConvertYaml; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/CommissioningModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/CommissioningModal.test.js.snap new file mode 100644 index 0000000..78c8983 --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/CommissioningModal.test.js.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Verify ReadAndConvertYaml renders correctly 1`] = ` + + + + Edit Control Loop Parameters + + +
+
+ +
+ +
+ + + + + +`; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/DeleteToscaTemplate.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/DeleteToscaTemplate.test.js.snap new file mode 100644 index 0000000..cd2288e --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/DeleteToscaTemplate.test.js.snap @@ -0,0 +1,20 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Verify DeleteToscaTemplate renders correctly 1`] = ` + + + +`; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/GetToscaTemplate.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/GetToscaTemplate.test.js.snap index 2c591d9..873afa7 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/GetToscaTemplate.test.js.snap +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/GetToscaTemplate.test.js.snap @@ -9,7 +9,7 @@ exports[`Verify GetToscaTemplate renders correctly 1`] = ` type="submit" variant="primary" > - Get Tosca Service Template + Pull Tosca Service Template `; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/ReadAndConvertYaml.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/ReadAndConvertYaml.test.js.snap index fab7801..d515474 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/ReadAndConvertYaml.test.js.snap +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/ReadAndConvertYaml.test.js.snap @@ -30,6 +30,19 @@ exports[`Verify ReadAndConvertYaml renders correctly 1`] = ` show={false} variant="danger" /> + + +

+ Delete Successful +

+ +
diff --git a/gui-clamp/ui-react/src/components/menu/MenuBar.js b/gui-clamp/ui-react/src/components/menu/MenuBar.js index f32d6c8..650196c 100644 --- a/gui-clamp/ui-react/src/components/menu/MenuBar.js +++ b/gui-clamp/ui-react/src/components/menu/MenuBar.js @@ -119,8 +119,9 @@ export default class MenuBar extends React.Component { Upload Tosca Instantiation Commissioning - View Tosca Template + Manage Commissioned Tosca Template Upload Tosca to Commissioning + Edit Control Loop Type Definitions Wiki diff --git a/gui-clamp/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap b/gui-clamp/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap index 9543c12..a1705ee 100644 --- a/gui-clamp/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap +++ b/gui-clamp/ui-react/src/components/menu/__snapshots__/MenuBar.test.js.snap @@ -1211,7 +1211,7 @@ exports[`Verify MenuBar Test the render method 1`] = ` disabled={false} to="/readToscaTemplate" > - View Tosca Template + Manage Commissioned Tosca Template Upload Tosca to Commissioning + + Edit Control Loop Type Definitions +