diff options
13 files changed, 407 insertions, 245 deletions
diff --git a/gui-clamp/ui-react-lib/libIndex.js b/gui-clamp/ui-react-lib/libIndex.js index 779e363..24e3072 100644 --- a/gui-clamp/ui-react-lib/libIndex.js +++ b/gui-clamp/ui-react-lib/libIndex.js @@ -59,8 +59,9 @@ export { default as MonitorInstantiation } from '../ui-react/src/components/dial export { default as InstantiationItem } from '../ui-react/src/components/dialogs/ControlLoop/InstantiationItem'; export { default as InstantiationElements } from '../ui-react/src/components/dialogs/ControlLoop/InstantiationElements'; export { default as InstantiationElementItem } from '../ui-react/src/components/dialogs/ControlLoop/InstantiationElementItem'; -export { default as InstanceModal } from '../ui-react/src/components/dialogs/ControlLoop/InstanceModal'; +export { default as InstancePropertiesModal } from '../ui-react/src/components/dialogs/ControlLoop/InstancePropertiesModal'; export { default as InstantiationManagementModal } from '../ui-react/src/components/dialogs/ControlLoop/InstantiationManagementModal'; +export { default as ChangeOrderStateModal } from '../ui-react/src/components/dialogs/ControlLoop/ChangeOrderStateModal'; export { default as InstantiationOrderStateChangeItem } from '../ui-react/src/components/dialogs/ControlLoop/InstantiationOrderStateChangeItem'; export { default as ControlLoopService } from '../ui-react/src/api/ControlLoopService'; export { default as GetLocalToscaFileForUpload } from '../ui-react/src/components/dialogs/ControlLoop/GetLocalToscaFileForUpload'; diff --git a/gui-clamp/ui-react/src/LoopUI.js b/gui-clamp/ui-react/src/LoopUI.js index 79943bf..e593a08 100644 --- a/gui-clamp/ui-react/src/LoopUI.js +++ b/gui-clamp/ui-react/src/LoopUI.js @@ -55,7 +55,8 @@ import ReadAndConvertYaml from "./components/dialogs/ControlLoop/ReadAndConvertY import MonitorInstantiation from "./components/dialogs/ControlLoop/MonitorInstantiation"; import GetLocalToscaFileForUpload from "./components/dialogs/ControlLoop/GetLocalToscaFileForUpload"; import CommissioningModal from "./components/dialogs/ControlLoop/CommissioningModal"; -import InstanceModal from "./components/dialogs/ControlLoop/InstanceModal"; +import InstancePropertiesModal from "./components/dialogs/ControlLoop/InstancePropertiesModal"; +import ChangeOrderStateModal from "./components/dialogs/ControlLoop/ChangeOrderStateModal"; import InstantiationManagementModal from "./components/dialogs/ControlLoop/InstantiationManagementModal"; const StyledMainDiv = styled.div` @@ -387,8 +388,9 @@ export default class LoopUI extends React.Component { showFailAlert={ this.showFailAlert }/>) } /> <Route path="/monitorInstantiation" render={ (routeProps) => (<MonitorInstantiation { ...routeProps } />) }/> - <Route path="/manageInstantiation" render={ (routeProps) => (<InstantiationManagementModal { ...routeProps } />) }/> - <Route path="/editControlLoopInstanceProperties" render={ (routeProps) => (<InstanceModal { ...routeProps } />) }/> + <Route path="/instantiationManagement" render={ (routeProps) => (<InstantiationManagementModal { ...routeProps } />) }/> + <Route path="/editControlLoopInstanceProperties" render={ (routeProps) => (<InstancePropertiesModal { ...routeProps } />) }/> + <Route path="/changeOrderState" render={ (routeProps) => (<ChangeOrderStateModal { ...routeProps } />) }/> </React.Fragment> ); } 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 abfcb8d..222b2a7 100644 --- a/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap +++ b/gui-clamp/ui-react/src/__snapshots__/LoopUI.test.js.snap @@ -90,13 +90,17 @@ exports[`Verify LoopUI Test the render method 1`] = ` render={[Function]} /> <Route - path="/manageInstantiation" + path="/instantiationManagement" render={[Function]} /> <Route path="/editControlLoopInstanceProperties" render={[Function]} /> + <Route + path="/changeOrderState" + render={[Function]} + /> <div /> <div> <Alert diff --git a/gui-clamp/ui-react/src/__snapshots__/OnapClamp.test.js.snap b/gui-clamp/ui-react/src/__snapshots__/OnapClamp.test.js.snap index a87127e..cc5541b 100644 --- a/gui-clamp/ui-react/src/__snapshots__/OnapClamp.test.js.snap +++ b/gui-clamp/ui-react/src/__snapshots__/OnapClamp.test.js.snap @@ -119,13 +119,17 @@ exports[`Verify OnapClamp Test the render method 1`] = ` render={[Function]} /> <Route - path="/manageInstantiation" + path="/instantiationManagement" render={[Function]} /> <Route path="/editControlLoopInstanceProperties" render={[Function]} /> + <Route + path="/changeOrderState" + render={[Function]} + /> <div /> <div> <Alert diff --git a/gui-clamp/ui-react/src/api/ControlLoopService.js b/gui-clamp/ui-react/src/api/ControlLoopService.js index 0d6e11c..96eb403 100644 --- a/gui-clamp/ui-react/src/api/ControlLoopService.js +++ b/gui-clamp/ui-react/src/api/ControlLoopService.js @@ -26,7 +26,7 @@ export default class ControlLoopService { return response } - static async createInstanceProperties(instancePropertiesTemplate, windowLocationPathname) { + static async createInstanceProperties(instanceName, instancePropertiesTemplate, windowLocationPathname) { const response = await fetch(windowLocationPathname + '/restservices/clds/v2/toscaControlLoop/postToscaInstanceProperties', { @@ -41,8 +41,29 @@ export default class ControlLoopService { return response } - static async getInstanceOrderState(windowLocationPathName) { - const response = await fetch(windowLocationPathName + '/restservices/clds/v2/toscaControlLoop/getInstantiationOrderState'); + static async deleteInstantiation(name, version, windowLocationPathName) { + console.log(windowLocationPathName); + const params = { + name: name, + version: version + } + + const response = await fetch(windowLocationPathName + '/restservices/clds/v2/toscaControlLoop/deleteToscaInstanceProperties?' + (new URLSearchParams(params)), { + method: 'DELETE', + credentials: 'same-origin', + }); + + const data = await response; + + return data; + } + + static async getInstanceOrderState(name, version, windowLocationPathName) { + const params = { + name: name, + version: version + } + const response = await fetch(windowLocationPathName + '/restservices/clds/v2/toscaControlLoop/getInstantiationOrderState'+ '?' + (new URLSearchParams(params))); const data = await response; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ChangeOrderStateModal.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ChangeOrderStateModal.js new file mode 100644 index 0000000..2c6d9aa --- /dev/null +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/ChangeOrderStateModal.js @@ -0,0 +1,176 @@ +/* + * ============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 styled from "styled-components"; +import Modal from "react-bootstrap/Modal"; +import Button from "react-bootstrap/Button"; +import React, { useContext, useEffect, useRef, useState } from "react"; +import InstantiationOrderStateChangeItem from "./InstantiationOrderStateChangeItem"; +import ControlLoopService from "../../../api/ControlLoopService"; +import { Alert, Container, Dropdown } from "react-bootstrap"; + +const ModalStyled = styled(Modal)` + @media (min-width: 800px) { + .modal-xl { + max-width: 96%; + } + } + background-color: transparent; +` + +const DivWhiteSpaceStyled = styled.div` + overflow: auto; + min-width: 100%; + max-height: 300px; + padding: 5px 5px 0px 5px; + text-align: center; +` + +const AlertStyled = styled(Alert)` + margin-top: 10px; +` + +const ChangeOrderStateModal = (props) => { + const [show, setShow] = useState(true); + const [windowLocationPathnameGet, setWindowLocationPathnameGet] = useState(''); + const [windowLocationPathNameSave, setWindowLocationPathNameSave] = useState(''); + const [controlLoopIdentifierList, setControlLoopIdentifierList] = useState([]); + const [orderedState, setOrderedState] = useState(''); + const [toscaOrderStateObject, setToscaOrderStateObject] = useState({}); + const [instantiationOrderStateError, setInstantiationOrderStateError] = useState(false); + const [instantiationOrderStateMsgError, setInstantiationOrderStateMsgError] = useState({}); + const [alertMessage, setAlertMessage] = useState(null); + + useEffect(async () => { + setWindowLocationPathnameGet(window.location.pathname); + + const instantiationOrderState = await ControlLoopService.getInstanceOrderState( + props.location.instantiationName, + props.location.instantiationVersion, windowLocationPathnameGet) + .catch(error => error.message); + + const orderStateJson = await instantiationOrderState.json(); + + console.log(orderStateJson); + + if (!instantiationOrderState.ok || orderStateJson['controlLoopIdentifierList'].length === 0) { + setInstantiationOrderStateError(true); + setInstantiationOrderStateMsgError(orderStateJson); + } else { + setControlLoopIdentifierList(orderStateJson['controlLoopIdentifierList']); + setOrderedState(orderStateJson['orderedState']); + } + }, []); + + const handleDropSelect = (event) => { + console.log("handleDropDownChange called"); + + const stateChangeObject = { + orderedState: event, + controlLoopIdentifierList: controlLoopIdentifierList + } + setToscaOrderStateObject(stateChangeObject); + setOrderedState(event); + } + + const handleSave = async () => { + console.log("handleSave called"); + setWindowLocationPathNameSave(window.location.pathname); + + const response = await ControlLoopService.changeInstanceOrderState( + toscaOrderStateObject, + windowLocationPathNameSave).catch(error => error.message); + + if (response.ok) { + successAlert(); + } else { + await errorAlert(response); + } + } + + const handleClose = () => { + console.log('handleClose called'); + setShow(false); + props.history.push('/'); + } + + const successAlert = () => { + console.log("successAlert called"); + setAlertMessage(<Alert variant="success"> + <Alert.Heading>Order State Changed Success</Alert.Heading> + <p>Order State Changed was successfully changed</p> + <hr/> + </Alert>); + } + + const errorAlert = async (response) => { + console.log("errorAlert called"); + setAlertMessage(<Alert variant="danger"> + <Alert.Heading>Order State Changed Failure</Alert.Heading> + <p>An error occurred while trying to change order state</p> + <p>Status code: { await response.status } : { response.statusText }</p> + <p>Status Text: { await response.text() }</p> + <hr/> + </Alert>); + } + + return ( + <ModalStyled size="sm" + show={ show } + onHide={ handleClose } + backdrop="static" + keyboard={ false }> + <Modal.Header closeButton> + <Modal.Title>Manage Instantiation</Modal.Title> + </Modal.Header> + <div style={ { padding: '5px 5px 0 5px' } }> + <Modal.Body> + <Container> + <Dropdown onSelect={ handleDropSelect }> + <Dropdown.Toggle variant="dark" id="dropdown-basic"> + Select Order State + </Dropdown.Toggle> + <Dropdown.Menu> + <Dropdown.Item eventKey="UNINITIALISED">UNINITIALISED</Dropdown.Item> + <Dropdown.Item eventKey="PASSIVE">PASSIVE</Dropdown.Item> + <Dropdown.Item eventKey="RUNNING">RUNNING</Dropdown.Item> + </Dropdown.Menu> + </Dropdown> + { + controlLoopIdentifierList.map((clIdList, index) => ( + <InstantiationOrderStateChangeItem title={ clIdList.name } orderState={ orderedState } index={ index } key={ index }/> + )) + } + </Container> + <AlertStyled show={ instantiationOrderStateError } + variant="danger">Can't get instantiation ordered state:<br/>{ JSON.stringify(instantiationOrderStateMsgError, null, 2) }</AlertStyled> + </Modal.Body> + <DivWhiteSpaceStyled> + { alertMessage } + </DivWhiteSpaceStyled> + </div> + <Modal.Footer> + <Button variant="primary" onClick={ handleSave }>Save</Button> + <Button variant="secondary" onClick={ handleClose }>Close</Button> + </Modal.Footer> + </ModalStyled> + ); +} + +export default ChangeOrderStateModal; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstanceModal.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstancePropertiesModal.js index 0380fa6..8343237 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstanceModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstancePropertiesModal.js @@ -24,6 +24,9 @@ import Button from "react-bootstrap/Button"; import ControlLoopService from "../../../api/ControlLoopService"; import { JSONEditor } from "@json-editor/json-editor"; import Alert from "react-bootstrap/Alert"; +import * as PropTypes from "prop-types"; +import Form from "react-bootstrap/Form"; +import Spinner from "react-bootstrap/Spinner"; const ModalStyled = styled(Modal)` @media (min-width: 800px) { @@ -50,17 +53,22 @@ const templateName = "ToscaServiceTemplateSimple"; const templateVersion = "1.0.0"; let tempJsonEditor = null; -const InstanceModal = (props) => { +function Fragment(props) { + return null; +} + +Fragment.propTypes = { children: PropTypes.node }; +const InstancePropertiesModal = (props) => { const [show, setShow] = useState(true); const [windowLocationPathname, setWindowLocationPathname] = useState(''); const [toscaFullTemplate, setToscaFullTemplate] = useState({}); - const [toscaFilteredInitialValues, setToscaFilteredInitialValues] = useState({}); - const [toscaJsonSchema, setToscaJsonSchema] = useState({}); const [jsonEditor, setJsonEditor] = useState(null); const [alertMessage, setAlertMessage] = useState(null); const [instancePropertiesGlobal, setInstancePropertiesGlobal] = useState({}); const [serviceTemplateResponseOk, setServiceTemplateResponseOk] = useState(true); const [instancePropertiesResponseOk, setInstancePropertiesResponseOk] = useState(true); + const [instanceName, setInstanceName] = useState('') + const [isLoading, setIsLoading] = useState(true); useEffect(async () => { const toscaInstanceProperties = await ControlLoopService.getCommonOrInstanceProperties(templateName, templateVersion, windowLocationPathname, false).catch(error => error.message); @@ -92,6 +100,8 @@ const InstanceModal = (props) => { const fullJsonSchemaTemplate = await fullTemplate.json(); setToscaFullTemplate(fullJsonSchemaTemplate); + console.log(fullJsonSchemaTemplate); + const filteredInitialStartValues = {}; const instanceProperties = await initialProperties.json().then(properties => { @@ -115,13 +125,10 @@ const InstanceModal = (props) => { filteredInitialStartValues[key] = propValues; }); - setToscaFilteredInitialValues(filteredInitialStartValues); - return filteredTemplateObj; }); const propertySchema = makeSchemaForInstanceProperties(instanceProperties); - setToscaJsonSchema(propertySchema); tempJsonEditor = createJsonEditor(propertySchema, filteredInitialStartValues); setJsonEditor(tempJsonEditor); @@ -159,6 +166,8 @@ const InstanceModal = (props) => { const getType = (pType) => { switch (pType) { + case "map": + return "string"; case "string": return "string"; case "integer": @@ -174,6 +183,8 @@ const InstanceModal = (props) => { } const createJsonEditor = (fullSchema, instanceProperties) => { + console.log(props.location.instanceName) + setIsLoading(false) JSONEditor.defaults.options.collapse = true; return new JSONEditor(document.getElementById("editor"), @@ -225,11 +236,13 @@ const InstanceModal = (props) => { const handleSave = async () => { console.log("handleSave called") + console.log("instanceName to be saved is: " + instanceName) + setWindowLocationPathname(window.location.pathname); updateTemplate(jsonEditor.getValue()); - const response = await ControlLoopService.createInstanceProperties(toscaFullTemplate, windowLocationPathname).catch(error => error.message); + const response = await ControlLoopService.createInstanceProperties(instanceName, toscaFullTemplate, windowLocationPathname).catch(error => error.message); if (response.ok) { successAlert(); @@ -238,6 +251,10 @@ const InstanceModal = (props) => { } } + const handleNameChange = (e) => { + setInstanceName(e.target.value) + } + const successAlert = () => { console.log("successAlert called"); setAlertMessage(<Alert variant="success"> @@ -265,7 +282,7 @@ const InstanceModal = (props) => { backdrop="static" keyboard={ false }> <Modal.Header closeButton> - <Modal.Title>Change Tosca Instance Properties</Modal.Title> + <Modal.Title>Create Tosca Instance Properties</Modal.Title> </Modal.Header> <div style={ { padding: '5px 5px 0 5px' } }> <Modal.Body> @@ -287,4 +304,4 @@ const InstanceModal = (props) => { ); } -export default InstanceModal; +export default InstancePropertiesModal; diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstanceModal.test.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstancePropertiesModal.test.js index 36a77d7..141999c 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstanceModal.test.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstancePropertiesModal.test.js @@ -19,36 +19,35 @@ import { mount, shallow } from "enzyme"; import React from "react"; -import InstanceModal from "./InstanceModal"; +import InstancePropertiesModal from "./InstancePropertiesModal"; import toJson from "enzyme-to-json"; import { createMemoryHistory } from "history"; -import MonitorInstantiation from "./MonitorInstantiation"; import { act } from "react-dom/test-utils"; describe('Verify MonitoringInstantiation', () => { it("renders without crashing", () => { - shallow(<InstanceModal />); + shallow(<InstancePropertiesModal />); }); it("renders correctly", () => { - const tree = shallow(<InstanceModal />); + const tree = shallow(<InstancePropertiesModal />); expect(toJson(tree)).toMatchSnapshot(); }); it('should have submit button element', () => { - const container = shallow(<InstanceModal/>) + const container = shallow(<InstancePropertiesModal/>) expect(container.find('[variant="primary"]').length).toEqual(1); }); it('should have close button element', () => { - const container = shallow(<InstanceModal/>) + const container = shallow(<InstancePropertiesModal/>) expect(container.find('[variant="secondary"]').length).toEqual(1); }); it('handleCreateUpdateToscaInstanceProperties called when submit button clicked', () => { const history = createMemoryHistory(); - const component = mount(<InstanceModal />) + const component = mount(<InstancePropertiesModal />) const logSpy = jest.spyOn(console, 'log'); act(() => { @@ -59,7 +58,7 @@ describe('Verify MonitoringInstantiation', () => { it('handleClose called when close button clicked', () => { const history = createMemoryHistory(); - const component = mount(<InstanceModal history={ history }/>) + const component = mount(<InstancePropertiesModal history={ history }/>) const logSpy = jest.spyOn(console, 'log'); act(() => { diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstantiationManagementModal.js b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstantiationManagementModal.js index c6c1eb9..a0a849c 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstantiationManagementModal.js +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/InstantiationManagementModal.js @@ -15,25 +15,28 @@ * * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= + * + * */ -import styled from "styled-components"; import Modal from "react-bootstrap/Modal"; +import { Alert, Container, Dropdown, Table } from "react-bootstrap"; import Button from "react-bootstrap/Button"; -import React, { useContext, useEffect, useRef, useState } from "react"; -import InstantiationOrderStateChangeItem from "./InstantiationOrderStateChangeItem"; +import React, { useEffect, useState } from "react"; +import styled from "styled-components"; +import { Link } from "react-router-dom"; import ControlLoopService from "../../../api/ControlLoopService"; -import { Alert, Container, Dropdown } from "react-bootstrap"; +import Row from "react-bootstrap/Row"; const ModalStyled = styled(Modal)` - @media (min-width: 800px) { - .modal-xl { - max-width: 96%; - } - } background-color: transparent; ` +const HorizontalSpace = styled.div` + padding-right: 2px; + padding-left: 2px; +`; + const DivWhiteSpaceStyled = styled.div` overflow: auto; min-width: 100%; @@ -41,55 +44,55 @@ const DivWhiteSpaceStyled = styled.div` padding: 5px 5px 0px 5px; text-align: center; ` - -const AlertStyled = styled(Alert)` - margin-top: 10px; -` - const InstantiationManagementModal = (props) => { const [show, setShow] = useState(true); - const [windowLocationPathnameGet, setWindowLocationPathnameGet] = useState(''); - const [windowLocationPathNameSave, setWindowLocationPathNameSave] = useState(''); - const [controlLoopIdentifierList, setControlLoopIdentifierList] = useState([]); - const [orderedState, setOrderedState] = useState(''); - const [toscaOrderStateObject, setToscaOrderStateObject] = useState({}); - const [instantiationOrderStateOk, setInstantiationOrderStateOk] = useState(true); - const [instantiationOrderStateError, setInstantiationOrderStateError] = useState({}); + const [windowLocationPathName, setWindowLocationPathName] = useState(''); + const [windowLocationPathNameDelete, setWindowLocationPathNameDelete] = useState(''); + + const [instantiationList, setInstantiationList] = useState([]); const [alertMessage, setAlertMessage] = useState(null); useEffect(async () => { - setWindowLocationPathnameGet(window.location.pathname); + setWindowLocationPathName(window.location.pathname); - const instantiationOrderState = await ControlLoopService.getInstanceOrderState(windowLocationPathnameGet) - .catch(error => error.message); + const response = await ControlLoopService.getControlLoopInstantiation(windowLocationPathName); - const orderStateJson = await instantiationOrderState.json(); + const instantiationListJson = await response.json(); - if (!instantiationOrderState.ok || orderStateJson['controlLoopIdentifierList'].length === 0) { - setInstantiationOrderStateOk(true); - setInstantiationOrderStateError(orderStateJson); - } else { - setControlLoopIdentifierList(orderStateJson['controlLoopIdentifierList']); - setOrderedState(orderStateJson['orderedState']); - } - }, []); + const parsedInstantiationList = instantiationListJson['controlLoopList'].map((instance, index) => { + return { + index: index, + name: instance['name'], + version: instance['version'], + orderedState: instance['orderedState'], + currentState: instance['state'], + disableDelete: instance['state'] !== 'UNINITIALISED' + } + }); - const handleDropSelect = (event) => { - console.log("handleDropDownChange called"); + setInstantiationList(parsedInstantiationList); + }, []); - const stateChangeObject = { - orderedState: event, - controlLoopIdentifierList: controlLoopIdentifierList + const getBackgroundColor = (index) => { + if (index % 2 === 0) { + return 'Silver'; } - setToscaOrderStateObject(stateChangeObject); - orderStateContext.orderState = stateChangeObject; + + return 'White'; } - const handleSave = async () => { - console.log("handleSave called"); - setWindowLocationPathNameSave(window.location.pathname); + const deleteInstantiationHandler = async (instantiation, index) => { + console.log("deleteInstantiationHandler called"); + setWindowLocationPathNameDelete(window.location.pathname); + + const name = instantiation.name; + const version = instantiation.version; + + console.log(window.location.pathname); + + const response = await ControlLoopService.deleteInstantiation(name, version, windowLocationPathNameDelete); - const response = await ControlLoopService.changeInstanceOrderState(toscaOrderStateObject, windowLocationPathNameSave).catch(error => error.message); + updateList(index); if (response.ok) { successAlert(); @@ -98,8 +101,34 @@ const InstantiationManagementModal = (props) => { } } + const updateList = (index) => { + console.log("updateList called") + console.log(instantiationList) + + const updatedList = [...instantiationList]; + updatedList.splice(index, 1); + + setInstantiationList(updatedList); + } + + const renderDeleteButton = (instantiation, index) => { + if (instantiation.disableDelete) { + return ( + <Button variant="outline-danger" type="null" + disabled={ true } + style={ { cursor: "not-allowed" } }>Delete</Button> + ); + + } else { + return ( + <Button variant="danger" type="null" + onClick={ async () => deleteInstantiationHandler(instantiation, index) }>Delete</Button> + ); + } + } + const handleClose = () => { - console.log('handleClose called'); + console.log("handleClose called"); setShow(false); props.history.push('/'); } @@ -107,8 +136,8 @@ const InstantiationManagementModal = (props) => { const successAlert = () => { console.log("successAlert called"); setAlertMessage(<Alert variant="success"> - <Alert.Heading>Order State Changed Success</Alert.Heading> - <p>Order State Changed was successfully changed</p> + <Alert.Heading>Deletion of Instantiation Success</Alert.Heading> + <p>Deletion of Instantiation was successful!</p> <hr/> </Alert>); } @@ -116,52 +145,93 @@ const InstantiationManagementModal = (props) => { const errorAlert = async (response) => { console.log("errorAlert called"); setAlertMessage(<Alert variant="danger"> - <Alert.Heading>Order State Changed Failure</Alert.Heading> - <p>An error occurred while trying to change order state</p> + <Alert.Heading>Deletion of Instantiation Failure</Alert.Heading> + <p>An error occurred while trying to delete instantiation</p> <p>Status code: { await response.status } : { response.statusText }</p> <p>Status Text: { await response.text() }</p> <hr/> </Alert>); } + const clearErrors = () => { + console.log("clearErrors called"); + setAlertMessage(null); + } + return ( - <ModalStyled size="sm" + <ModalStyled size="xl" show={ show } onHide={ handleClose } backdrop="static" keyboard={ false }> <Modal.Header closeButton> - <Modal.Title>Manage Instantiation</Modal.Title> + <Modal.Title>Manage Instances</Modal.Title> </Modal.Header> - <div style={ { padding: '5px 5px 0 5px' } }> - <Modal.Body> - <Container> - <Dropdown onSelect={ handleDropSelect }> - <Dropdown.Toggle variant="dark" id="dropdown-basic"> - Select Order State - </Dropdown.Toggle> - <Dropdown.Menu> - <Dropdown.Item eventKey="UNINITIALISED">UNINITIALISED</Dropdown.Item> - <Dropdown.Item eventKey="PASSIVE">PASSIVE</Dropdown.Item> - <Dropdown.Item eventKey="RUNNING">RUNNING</Dropdown.Item> - </Dropdown.Menu> - </Dropdown> - { - controlLoopIdentifierList.map((clIdList, index) => ( - <InstantiationOrderStateChangeItem title={ clIdList.name } index={ index } key={ index } /> - )) - } - </Container> - <AlertStyled show={ !instantiationOrderStateOk } - variant="danger">Can't get instantiation ordered state:<br/>{ JSON.stringify(instantiationOrderStateError, null, 2) }</AlertStyled> - </Modal.Body> + <Modal.Body> + <Container> + <Row> + <Link to={ { pathname: "/editControlLoopInstanceProperties" } }> + <Button variant="primary" type="null">Create Instance</Button> + </Link> + <HorizontalSpace/> + <Link to={ { pathname: "/monitorInstantiation" } }> + <Button variant="secondary" type="null">Monitor Instantiations</Button> + </Link> + </Row> + </Container> + <Table bordered style={ { marginTop: '10px' } }> + <thead> + <tr> + <th>#</th> + <th style={ { textAlign: "center" } }>Instantiation Name</th> + <th style={ { textAlign: "center" } }>Edit Instantiation</th> + <th style={ { textAlign: "center" } }>Delete Instantiation</th> + <th style={ { textAlign: "center" } }>Change Order State</th> + <th style={ { textAlign: "center" } }>Instantiation Order State</th> + <th style={ { textAlign: "center" } }>Instantiation Current State</th> + </tr> + </thead> + <tbody> + { instantiationList.map((instantiation, index) => { + return ( + <tr style={ { backgroundColor: getBackgroundColor(index) } } key={ index } className="instantiationList"> + <td>{ index + 1 }</td> + <td>{ instantiation.name }</td> + <td style={ { textAlign: "center" } }> + <Link to={ { + pathname: "editControlLoopInstanceProperties", + } } state={ instantiation.name }> + <Button variant="outline-success" type="null" + disabled={ true } + style={ { cursor: "not-allowed" } }>Edit</Button> + </Link> + </td> + <td style={ { textAlign: "center" } }> + { renderDeleteButton(instantiation, index) } + </td> + <td style={ { textAlign: "center" } }> + <Link to={ { + pathname: "changeOrderState", + instantiationName: instantiation.name, + instantiationVersion: instantiation.version + } }> + <Button variant="secondary" type="null">Change</Button> + </Link> + </td> + <td>{ instantiation.orderedState }</td> + <td>{ instantiation.currentState }</td> + </tr> + ) + }) } + </tbody> + </Table> <DivWhiteSpaceStyled> { alertMessage } </DivWhiteSpaceStyled> - </div> + </Modal.Body> <Modal.Footer> - <Button variant="primary" onClick={ handleSave }>Save</Button> - <Button variant="secondary" onClick={ handleClose }>Close</Button> + <Button variant="secondary" type="null" onClick={ clearErrors }>Clear Error Message</Button> + <Button variant="secondary" type="null" onClick={ handleClose }>Close</Button> </Modal.Footer> </ModalStyled> ); diff --git a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/InstanceModal.test.js.snap b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/InstancePropertiesModal.test.js.snap index ba7caf9..96b500e 100644 --- a/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/InstanceModal.test.js.snap +++ b/gui-clamp/ui-react/src/components/dialogs/ControlLoop/__snapshots__/InstancePropertiesModal.test.js.snap @@ -13,7 +13,7 @@ exports[`Verify MonitoringInstantiation renders correctly 1`] = ` closeLabel="Close" > <ModalTitle> - Change Tosca Instance Properties + Create Tosca Instance Properties </ModalTitle> </ModalHeader> <div diff --git a/gui-clamp/ui-react/src/components/dialogs/InstantiationManagementModal.test.js b/gui-clamp/ui-react/src/components/dialogs/InstantiationManagementModal.test.js index 61f8c1a..25292d0 100644 --- a/gui-clamp/ui-react/src/components/dialogs/InstantiationManagementModal.test.js +++ b/gui-clamp/ui-react/src/components/dialogs/InstantiationManagementModal.test.js @@ -22,27 +22,27 @@ import React from "react"; import toJson from "enzyme-to-json"; import { createMemoryHistory } from "history"; import { act } from "react-dom/test-utils"; -import InstantiationManagementModal from "./ControlLoop/InstantiationManagementModal"; +import ChangeOrderStateModal from "./ControlLoop/ChangeOrderStateModal"; describe('Verify InstantiationManagementModal', () => { it("renders without crashing", () => { - shallow(<InstantiationManagementModal />); + shallow(<ChangeOrderStateModal />); }); it("renders correctly", () => { - const tree = shallow(<InstantiationManagementModal />); + const tree = shallow(<ChangeOrderStateModal />); expect(toJson(tree)).toMatchSnapshot(); }); it('should have save button element', () => { - const container = shallow(<InstantiationManagementModal/>) + const container = shallow(<ChangeOrderStateModal/>) expect(container.find('[variant="primary"]').length).toEqual(1); }); it('handleSave called when save button clicked', () => { const history = createMemoryHistory(); - const component = mount(<InstantiationManagementModal history={ history }/>) + const component = mount(<ChangeOrderStateModal history={ history }/>) const logSpy = jest.spyOn(console, 'log'); act(() => { @@ -52,13 +52,13 @@ describe('Verify InstantiationManagementModal', () => { }); it('should have close button element', () => { - const container = shallow(<InstantiationManagementModal/>) + const container = shallow(<ChangeOrderStateModal/>) expect(container.find('[variant="secondary"]').length).toEqual(1); }); it('handleClose called when close button clicked', () => { const history = createMemoryHistory(); - const component = mount(<InstantiationManagementModal history={ history }/>) + const component = mount(<ChangeOrderStateModal history={ history }/>) const logSpy = jest.spyOn(console, 'log'); act(() => { diff --git a/gui-clamp/ui-react/src/components/menu/MenuBar.js b/gui-clamp/ui-react/src/components/menu/MenuBar.js index 99480a9..59cff22 100644 --- a/gui-clamp/ui-react/src/components/menu/MenuBar.js +++ b/gui-clamp/ui-react/src/components/menu/MenuBar.js @@ -115,9 +115,7 @@ export default class MenuBar extends React.Component { </StyledNavDropdown> <StyledNavDropdown title="TOSCA Control Loop"> <NavDropdown.Header>Instantiation</NavDropdown.Header> - <NavDropdown.Item as={ StyledLink } to="/monitorInstantiation">Monitor Instantiation</NavDropdown.Item> - <NavDropdown.Item as={ StyledLink } to="/manageInstantiation">Manage Instantiation</NavDropdown.Item> - <NavDropdown.Item as={ StyledLink } to="/editControlLoopInstanceProperties">Edit Control Loop Instance Properties</NavDropdown.Item> + <NavDropdown.Item as={ StyledLink } to="/instantiationManagement">Instantiation Management</NavDropdown.Item> <NavDropdown.Divider/> <NavDropdown.Header>Commissioning</NavDropdown.Header> <NavDropdown.Item as={ StyledLink } to="/readToscaTemplate">Manage Commissioned Tosca Template</NavDropdown.Item> 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 36132ff..dbae793 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 @@ -1071,139 +1071,9 @@ exports[`Verify MenuBar Test the render method 1`] = ` } } disabled={false} - to="/monitorInstantiation" + to="/instantiationManagement" > - Monitor Instantiation - </DropdownItem> - <DropdownItem - as={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": e { - "baseHash": -715527839, - "baseStyle": undefined, - "componentId": "sc-bdnxRM", - "isStatic": false, - "rules": Array [ - " - color: ", - [Function], - "; - background-color: ", - [Function], - "; - font-weight: normal; - display: block; - width: 100%; - padding: .25rem 1.5rem; - clear: both; - text-align: inherit; - white-space: nowrap; - border: 0; - - :hover { - text-decoration: none; - background-color: ", - [Function], - "; - color: ", - [Function], - "; - } -", - ], - "staticRulesId": "", - }, - "foldedComponentIds": Array [], - "render": [Function], - "shouldForwardProp": undefined, - "styledComponentId": "sc-bdnxRM", - "target": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "innerRef": [Function], - "onClick": [Function], - "replace": [Function], - "target": [Function], - "to": [Function], - }, - "render": [Function], - }, - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - disabled={false} - to="/manageInstantiation" - > - Manage Instantiation - </DropdownItem> - <DropdownItem - as={ - Object { - "$$typeof": Symbol(react.forward_ref), - "attrs": Array [], - "componentStyle": e { - "baseHash": -715527839, - "baseStyle": undefined, - "componentId": "sc-bdnxRM", - "isStatic": false, - "rules": Array [ - " - color: ", - [Function], - "; - background-color: ", - [Function], - "; - font-weight: normal; - display: block; - width: 100%; - padding: .25rem 1.5rem; - clear: both; - text-align: inherit; - white-space: nowrap; - border: 0; - - :hover { - text-decoration: none; - background-color: ", - [Function], - "; - color: ", - [Function], - "; - } -", - ], - "staticRulesId": "", - }, - "foldedComponentIds": Array [], - "render": [Function], - "shouldForwardProp": undefined, - "styledComponentId": "sc-bdnxRM", - "target": Object { - "$$typeof": Symbol(react.forward_ref), - "propTypes": Object { - "innerRef": [Function], - "onClick": [Function], - "replace": [Function], - "target": [Function], - "to": [Function], - }, - "render": [Function], - }, - "toString": [Function], - "warnTooManyClasses": [Function], - "withComponent": [Function], - } - } - disabled={false} - to="/editControlLoopInstanceProperties" - > - Edit Control Loop Instance Properties + Instantiation Management </DropdownItem> <DropdownDivider role="separator" |