diff options
Diffstat (limited to 'ui-react/src/components')
4 files changed, 90 insertions, 49 deletions
diff --git a/ui-react/src/components/dialogs/PerformActions.js b/ui-react/src/components/dialogs/PerformActions.js index cf5a3c20e..f6001e21f 100644 --- a/ui-react/src/components/dialogs/PerformActions.js +++ b/ui-react/src/components/dialogs/PerformActions.js @@ -22,24 +22,19 @@ */ import React from 'react'; import LoopActionService from '../../api/LoopActionService'; -import Spinner from 'react-bootstrap/Spinner' -import styled from 'styled-components'; -const StyledSpinnerDiv = styled.div` - justify-content: center !important; - display: flex !important; -`; export default class PerformActions extends React.Component { state = { loopName: this.props.loopCache.getLoopName(), loopAction: this.props.loopAction }; + constructor(props, context) { super(props, context); - this.refreshStatus = this.refreshStatus.bind(this); } + componentWillReceiveProps(newProps) { this.setState({ loopName: newProps.loopCache.getLoopName(), @@ -51,35 +46,50 @@ export default class PerformActions extends React.Component { const action = this.state.loopAction; const loopName = this.state.loopName; - LoopActionService.performAction(loopName, action).then(pars => { + if (action === 'delete') { + if (window.confirm('You are about to remove Control Loop Model "' + loopName + + '". Select OK to continue with deletion or Cancel to keep the model.') === false) { + return; + } + } + + this.props.setBusyLoading(); // Alert top level to start block user clicks + + LoopActionService.performAction(loopName, action) + .then(pars => { this.props.showSucAlert("Action " + action + " successfully performed"); - // refresh status and update loop logs - this.refreshStatus(loopName); + if (action === 'delete') { + this.props.updateLoopFunction(null); + this.props.history.push('/'); + } else { + // refresh status and update loop logs + this.refreshStatus(loopName); + } }) .catch(error => { this.props.showFailAlert("Action " + action + " failed"); // refresh status and update loop logs this.refreshStatus(loopName); - }); - + }) + .finally(() => this.props.clearBusyLoading()); } refreshStatus(loopName) { - LoopActionService.refreshStatus(loopName).then(data => { + + this.props.setBusyLoading(); + + LoopActionService.refreshStatus(loopName) + .then(data => { this.props.updateLoopFunction(data); this.props.history.push('/'); }) - .catch(error => { + .catch(error => { this.props.history.push('/'); - }); + }) + .finally(() => this.props.clearBusyLoading()); } render() { - return ( - <StyledSpinnerDiv> - <Spinner animation="border" role="status"> - </Spinner> - </StyledSpinnerDiv> - ); + return null; } } diff --git a/ui-react/src/components/dialogs/PerformActions.test.js b/ui-react/src/components/dialogs/PerformActions.test.js index b833a929d..c91c2f675 100644 --- a/ui-react/src/components/dialogs/PerformActions.test.js +++ b/ui-react/src/components/dialogs/PerformActions.test.js @@ -38,6 +38,8 @@ describe('Verify PerformActions', () => { const updateLoopFunction = jest.fn(); const showSucAlert = jest.fn(); const showFailAlert = jest.fn(); + const setBusyLoading = jest.fn(); + const clearBusyLoading = jest.fn(); LoopActionService.refreshStatus = jest.fn().mockImplementation(() => { return Promise.resolve({ @@ -47,7 +49,7 @@ describe('Verify PerformActions', () => { }); }); const component = shallow(<PerformActions loopCache={loopCache} - loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} />) + loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} setBusyLoading={setBusyLoading} clearBusyLoading={clearBusyLoading}/>) await flushPromises(); component.update(); @@ -60,6 +62,8 @@ describe('Verify PerformActions', () => { const updateLoopFunction = jest.fn(); const showSucAlert = jest.fn(); const showFailAlert = jest.fn(); + const setBusyLoading = jest.fn(); + const clearBusyLoading = jest.fn(); LoopActionService.performAction = jest.fn().mockImplementation(() => { return Promise.resolve({ @@ -76,7 +80,7 @@ describe('Verify PerformActions', () => { }); }); const component = shallow(<PerformActions loopCache={loopCache} - loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} />) + loopAction="submit" history={historyMock} updateLoopFunction={updateLoopFunction} showSucAlert={showSucAlert} showFailAlert={showFailAlert} setBusyLoading={setBusyLoading} clearBusyLoading={clearBusyLoading}/>) await flushPromises(); component.update(); diff --git a/ui-react/src/components/dialogs/Policy/PolicyModal.js b/ui-react/src/components/dialogs/Policy/PolicyModal.js index d3b427396..6b1ebe178 100644 --- a/ui-react/src/components/dialogs/Policy/PolicyModal.js +++ b/ui-react/src/components/dialogs/Policy/PolicyModal.js @@ -34,11 +34,16 @@ import LoopCache from '../../../api/LoopCache'; import JSONEditor from '@json-editor/json-editor'; import Alert from 'react-bootstrap/Alert'; import OnapConstant from '../../../utils/OnapConstants'; +import OnapUtils from '../../../utils/OnapUtils'; const ModalStyled = styled(Modal)` background-color: transparent; ` +const DivWhiteSpaceStyled = styled.div` + white-space: pre; +` + export default class PolicyModal extends React.Component { state = { @@ -70,42 +75,49 @@ export default class PolicyModal extends React.Component { this.renderPdpGroupDropDown = this.renderPdpGroupDropDown.bind(this); this.renderOpenLoopMessage = this.renderOpenLoopMessage.bind(this); this.renderModalTitle = this.renderModalTitle.bind(this); + this.readOnly = props.readOnly !== undefined ? props.readOnly : false; } handleSave() { - var errors = this.state.jsonEditor.validate(); var editorData = this.state.jsonEditor.getValue(); + var errors = this.state.jsonEditor.validate(); + errors = errors.concat(this.customValidation(editorData, this.state.loopCache.getTemplateName())); if (errors.length !== 0) { console.error("Errors detected during policy data validation ", errors); this.setState({ - showFailAlert: true, - showMessage: "Errors detected during policy data validation " + errors - }); + showFailAlert: true, + showMessage: 'Errors detected during policy data validation:\n' + OnapUtils.jsonEditorErrorFormatter(errors) + }); return; } else { console.info("NO validation errors found in policy data"); if (this.state.policyInstanceType === OnapConstant.microServiceType) { - this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData); - this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup); - LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => { - this.setState({ show: false }); - this.props.history.push('/'); - this.props.loadLoopFunction(this.state.loopCache.getLoopName()); - }); + this.state.loopCache.updateMicroServiceProperties(this.state.policyName, editorData); + this.state.loopCache.updateMicroServicePdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup); + LoopService.setMicroServiceProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getMicroServiceForName(this.state.policyName)).then(resp => { + this.setState({ show: false }); + this.props.history.push('/'); + this.props.loadLoopFunction(this.state.loopCache.getLoopName()); + }); } else if (this.state.policyInstanceType === OnapConstant.operationalPolicyType) { this.state.loopCache.updateOperationalPolicyProperties(this.state.policyName, editorData); this.state.loopCache.updateOperationalPolicyPdpGroup(this.state.policyName, this.state.chosenPdpGroup, this.state.chosenPdpSubgroup); LoopService.setOperationalPolicyProperties(this.state.loopCache.getLoopName(), this.state.loopCache.getOperationalPolicies()).then(resp => { this.setState({ show: false }); - this.props.history.push('/'); + this.props.history.push('/'); this.props.loadLoopFunction(this.state.loopCache.getLoopName()); }); } } } + customValidation(editorData, templateName) { + // method for sub-classes to override with customized validation + return []; + } + handleClose() { this.setState({ show: false }); this.props.history.push('/'); @@ -115,6 +127,15 @@ export default class PolicyModal extends React.Component { this.renderJsonEditor(); } + componentDidUpdate() { + if (this.state.showSucAlert === true || this.state.showFailAlert === true) { + let modalElement = document.getElementById("policyModal") + if (modalElement) { + modalElement.scrollTo(0, 0); + } + } + } + createJsonEditor(toscaModel, editorData) { JSONEditor.defaults.themes.myBootstrap4 = JSONEditor.defaults.themes.bootstrap4.extend({ getTab: function(text,tabId) { @@ -313,12 +334,16 @@ export default class PolicyModal extends React.Component { <Modal.Header closeButton> {this.renderModalTitle()} </Modal.Header> - <Alert variant="success" show={this.state.showSucAlert} onClose={this.disableAlert} dismissible> - {this.state.showMessage} - </Alert> - <Alert variant="danger" show={this.state.showFailAlert} onClose={this.disableAlert} dismissible> - {this.state.showMessage} - </Alert> + <Alert variant="success" show={this.state.showSucAlert} 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> {this.renderOpenLoopMessage()} <div id="editor" /> @@ -330,4 +355,4 @@ export default class PolicyModal extends React.Component { </ModalStyled> ); } -}
\ No newline at end of file +} diff --git a/ui-react/src/components/loop_viewer/svg/SvgGenerator.js b/ui-react/src/components/loop_viewer/svg/SvgGenerator.js index d718c2e44..7070455e7 100644 --- a/ui-react/src/components/loop_viewer/svg/SvgGenerator.js +++ b/ui-react/src/components/loop_viewer/svg/SvgGenerator.js @@ -70,13 +70,15 @@ class SvgGenerator extends React.Component { } handleSvgClick(event) { - if (this.state.clickable) { - console.debug("svg click event received"); - var elementName = event.target.parentNode.getAttribute('policyId'); - console.info("SVG element clicked", elementName); - if (elementName !== null) { - this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName); - } + console.debug("svg click event received"); + if (this.state.clickable) { + var elementName = event.target.parentNode.getAttribute('policyId'); + console.info("SVG element clicked", elementName); + // Only allow movement to policy editing IF there busyLoadingCOunt is 0, + // meaning we are not waiting for refreshStatus to complete, for example + if (elementName !== null && !this.props.isBusyLoading()) { + this.props.history.push("/policyModal/"+event.target.parentNode.getAttribute('policyType')+"/"+elementName); + } } } |