diff options
author | atulpurohit <atul.purohit1@vodafone.com> | 2019-11-05 14:31:56 +0530 |
---|---|---|
committer | Ofir Sonsino <ofir.sonsino@intl.att.com> | 2020-01-13 09:33:40 +0000 |
commit | 8b346842194edb8a9e8c4cd2764ae8ebbce988f0 (patch) | |
tree | 3ea20981d4cdd5858c4a99eb49c0370503c3c6cb /openecomp-ui/src/sdc-app/onboarding | |
parent | 0ef638b2eb44c9f473e5ad8bea119845d968fde7 (diff) |
Refresh option in validation result page
Issue-ID: SDC-2585
Co-authored-by: nikhil.soni@vodafone.com
Signed-off-by: atulpurohit <atul.purohit1@vodafone.com>
Change-Id: I78f1385d219837c300cb33aff82b7459f137babb
Signed-off-by: atulpurohit <atul.purohit1@vodafone.com>
Diffstat (limited to 'openecomp-ui/src/sdc-app/onboarding')
13 files changed, 664 insertions, 281 deletions
diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js index 754c11206d..688806cf9a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js @@ -49,6 +49,8 @@ import FeaturesActionHelper from 'sdc-app/features/FeaturesActionHelper.js'; import { notificationActions } from 'nfvo-components/notification/NotificationsConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SoftwareProductValidationActionHelper from './softwareProduct/validation/SoftwareProductValidationActionHelper.js'; +import SoftwareProductValidationResultsViewActionHelper from './softwareProduct/validationResults/SoftwareProductValidationResultsViewActionHelper.js'; + import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; function setCurrentScreen(dispatch, screen, props = {}) { @@ -446,11 +448,26 @@ const OnboardingActionHelper = { dispatch, { softwareProductId, version, status } ) { - setCurrentScreen( - dispatch, - enums.SCREEN.SOFTWARE_PRODUCT_VALIDATION_RESULTS, - { softwareProductId, version, status } - ); + SoftwareProductValidationResultsViewActionHelper.fetchVspChecks( + dispatch + ) + .then(() => { + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_VALIDATION_RESULTS, + { softwareProductId, version, status } + ); + }) + .catch(error => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: 'ERROR', + msg: error.responseJSON.message, + cancelButtonText: i18n('OK') + } + }); + }); }, navigateToSoftwareProductDependencies( diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js index 7b8c426964..dcec5c683f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js @@ -46,6 +46,7 @@ import SoftwareProductComponentsComputeFlavorListReducer from './components/comp import SoftwareProductComponentsComputeFlavorReducer from './components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js'; import { createPlainDataReducer } from 'sdc-app/common/reducers/PlainDataReducer.js'; import SoftwareProductDependenciesReducer from './dependencies/SoftwareProductDependenciesReducer.js'; +import SoftwareProductValidationResultsViewReducer from './validationResults/SoftwareProductValidationResultsViewReducer.js'; import { createJSONSchemaReducer, createComposedJSONSchemaReducer @@ -78,6 +79,9 @@ export default combineReducers({ softwareProductValidation: createPlainDataReducer( SoftwareProductValidationReducer ), + softwareProductValidationResult: createPlainDataReducer( + SoftwareProductValidationResultsViewReducer + ), softwareProductProcesses: combineReducers({ processesList: SoftwareProductProcessesListReducer, processesEditor: createPlainDataReducer( diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidation.js index a6237e878a..27d9b5ebf8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidation.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidation.js @@ -30,14 +30,21 @@ export const mapActionsToProps = dispatch => { SoftwareProductValidationActionHelper.onErrorThrown(dispatch, msg); }, - onTestSubmit: (softwareProductId, version, status, tests) => { + onTestSubmit: ( + softwareProductId, + version, + status, + tests, + requestId + ) => { SoftwareProductValidationActionHelper.navigateToSoftwareProductValidationResults( dispatch, { softwareProductId, version, status, - tests + tests, + requestId } ); }, diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationActionHelper.js index 1ebb94b77c..fc6de3e2eb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationActionHelper.js @@ -15,18 +15,40 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import getValue from 'nfvo-utils/getValue.js'; import { actionTypes } from './SoftwareProductValidationConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -function postVSPCertificationChecks(tests) { +function createCertificationFormData(tests) { + var formData = new FormData(); + var testData = []; + for (var test of tests) { + if (test.files) { + for (var file of test.files) { + formData.append('files', file.file, file.name); + } + } + delete test.files; + testData.push(test); + } + formData.append('testdata', JSON.stringify(testData)); + + return formData; +} +function postVSPCertificationChecks( + tests, + version, + softwareProductId, + requestId +) { const restPrefix = Configuration.get('restPrefix'); + var id = version.id; + var formData = createCertificationFormData(tests); return RestAPIUtil.post( - `${restPrefix}/v1.0/externaltesting/executions`, - getValue(tests) + `${restPrefix}/v1.0/externaltesting/executions?vspId=${softwareProductId}&vspVersionId=${id}&requestId=${requestId}`, + formData ); } @@ -35,41 +57,59 @@ function fetchVspChecks() { return RestAPIUtil.fetch(`${restPrefix}/v1.0/externaltesting/testcasetree`); } +function extractEndPoint(tests) { + return [...new Set(tests.map(test => test.endpoint))]; +} const SoftwareProductValidationActionHelper = { navigateToSoftwareProductValidationResults( dispatch, - { softwareProductId, version, status, tests } + { softwareProductId, version, status, tests, requestId } ) { - postVSPCertificationChecks(tests) - .then(response => { - dispatch({ - type: actionTypes.POST_VSP_TESTS, - vspTestResults: response - }); - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_VALIDATION_RESULTS, - screenType: screenTypes.SOFTWARE_PRODUCT, - props: { - softwareProductId, - version, - status - } - }); - }) - .catch(error => { - let errMessage = error.message || error.responseJSON.message; - let title = error.responseJSON - ? error.responseJSON.status - : i18n('Error'); - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: title, - msg: errMessage, - cancelButtonText: i18n('OK') - } + return new Promise((resolve, reject) => { + postVSPCertificationChecks( + tests, + version, + softwareProductId, + requestId + ) + .then(response => { + var testResultKeys = {}; + testResultKeys.endPoints = extractEndPoint(tests); + testResultKeys.requestId = requestId; + dispatch({ + type: actionTypes.POST_VSP_TESTS, + vspTestResults: response, + testResultKeys: testResultKeys + }); + ScreensHelper.loadScreen(dispatch, { + screen: + enums.SCREEN.SOFTWARE_PRODUCT_VALIDATION_RESULTS, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + version, + status + } + }); + resolve(response); + }) + .catch(error => { + let errMessage = + error.message || error.responseJSON.message; + let title = error.responseJSON + ? error.responseJSON.status + : i18n('Error'); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: title, + msg: errMessage, + cancelButtonText: i18n('OK') + } + }); + reject(error); }); - }); + }); }, fetchVspChecks(dispatch) { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationReducer.js index 4513e23205..4a7f257e73 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationReducer.js @@ -20,7 +20,8 @@ export default (state = {}, action) => { case actionTypes.POST_VSP_TESTS: return { ...state, - vspTestResults: action.vspTestResults + vspTestResults: action.vspTestResults, + testResultKeys: action.testResultKeys }; case actionTypes.FETCH_VSP_CHECKS: return { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationView.jsx index fac69616bb..36cc7c7672 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/SoftwareProductValidationView.jsx @@ -15,7 +15,7 @@ */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; - +import Configuration from 'sdc-app/config/Configuration.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import { Button } from 'onap-ui-react'; import { Tab, Tabs } from 'onap-ui-react'; @@ -74,7 +74,9 @@ class SoftwareProductValidation extends Component { buildChildElements(setItem, testScenario) { let parentElement = {}; parentElement.value = setItem.name; - parentElement.label = setItem.description; + parentElement.label = setItem.description + ? setItem.description + : setItem.name; parentElement.children = []; if (setItem.children !== undefined) { setItem.children.forEach(element => { @@ -89,11 +91,13 @@ class SoftwareProductValidation extends Component { } if (setItem.tests !== undefined) { setItem.tests.forEach(element => { - parentElement.children.push({ - value: element.testCaseName, - label: element.description - }); - this.setMapAndGeneralData(element, testScenario); + if (element.inputs) { + parentElement.children.push({ + value: element.testCaseName, + label: element.testCaseName + }); + this.setMapAndGeneralData(element, testScenario); + } }); } return parentElement; @@ -115,6 +119,8 @@ class SoftwareProductValidation extends Component { parentNode.children.push({ value: element.testCaseName, label: element.description + ? element.description + : element.testCaseName }); this.setMapAndGeneralData(element, scenario); }); @@ -129,10 +135,11 @@ class SoftwareProductValidation extends Component { let certificationList = []; let { setVspTestsMap } = this.props; if (Object.keys(res).length !== 0 && res.children) { + let allTestScenario = Configuration.get('allTestScenario'); res.children.forEach(element => { if (element.name === 'certification') { certificationData = element; - } else if (element.name === 'compliance') { + } else if (element.name === allTestScenario) { complianceData = element; } }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/inputs/VspValidationInputsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/inputs/VspValidationInputsView.jsx index 8888c92f6d..cda3fe2c92 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/inputs/VspValidationInputsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/inputs/VspValidationInputsView.jsx @@ -15,7 +15,7 @@ */ import React, { Component } from 'react'; import PropTypes from 'prop-types'; - +import UUID from 'uuid-js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import { Button } from 'onap-ui-react'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; @@ -35,23 +35,51 @@ class VspInputs extends React.Component { changeInputs(e, check, parameterName) { let { testsRequest, generalInfo, setTestsRequest } = this.props; - testsRequest[check].parameters[parameterName] = e; + if (e instanceof File) { + var timestamp = new Date().getTime(); + var fileExtension = ( + e.name.match(/[^\\\/]\.([^.\\\/]+)$/) || [null] + ).pop(); + var fileName = fileExtension + ? timestamp + '.' + fileExtension + : timestamp; + testsRequest[check].parameters[parameterName] = + 'file://' + fileName; + + testsRequest[check].files = testsRequest[check].files + ? testsRequest[check].files + : []; + testsRequest[check].files.push({ file: e, name: fileName }); + } else { + testsRequest[check].parameters[parameterName] = e; + } + generalInfo[check][parameterName] = { isValid: true, errorText: '' }; setTestsRequest(testsRequest, generalInfo); } - renderInputs(check) { + renderInputs(check, indexKey) { let { vspTestsMap, testsRequest, generalInfo } = this.props; return ( - <div className="div-clear-both"> + <div key={indexKey} className="div-clear-both"> <GridSection title={i18n('{title} Inputs :', { - title: vspTestsMap[check].title + title: vspTestsMap[check].title.split(/\r?\n/)[0] })}> {vspTestsMap[check].parameters.map((parameter, index) => { + parameter.metadata = parameter.metadata + ? parameter.metadata + : {}; + if ( + !this.props.filterField(parameter) || + parameter.metadata.hidden + ) { + return; + } if ( - parameter.type === 'text' && - !parameter.metadata.hidden + parameter.type === 'text' || + parameter.type === 'string' || + parameter.type === 'json' ) { return ( <GridItem key={index}> @@ -112,6 +140,31 @@ class VspInputs extends React.Component { </Input> </GridItem> ); + } else if (parameter.type === 'binary') { + return ( + <GridItem key={index}> + <Input + label={parameter.description} + type="file" + isRequired={!parameter.isOptional} + isValid={ + generalInfo[check][parameter.name] + .isValid + } + errorText={ + generalInfo[check][parameter.name] + .errorText + } + onChange={e => { + this.changeInputs( + e.target ? e.target.value : e, + check, + parameter.name + ); + }} + /> + </GridItem> + ); } })} </GridSection> @@ -127,18 +180,18 @@ class VspInputs extends React.Component { } = this.props; return ( <div> - {complianceChecked.map(complianceCheck => { + {complianceChecked.map((complianceCheck, index) => { if (vspTestsMap[complianceCheck].parameters.length === 0) { return <div />; } else { - return this.renderInputs(complianceCheck); + return this.renderInputs(complianceCheck, index); } })} - {certificationChecked.map(certificateCheck => { + {certificationChecked.map((certificateCheck, index) => { if (vspTestsMap[certificateCheck].parameters.length === 0) { return <div />; } else { - return this.renderInputs(certificateCheck); + return this.renderInputs(certificateCheck, index); } })} </div> @@ -159,7 +212,19 @@ class VspValidationInputs extends Component { shouldComponentUpdate() { return true; } - + filterField(parameter) { + if ( + parameter.name === 'host-username' || + parameter.name === 'vsp' || + parameter.name === 'vsp-zip' || + parameter.name === 'host-password' || + parameter.name === 'host-url' + ) { + return false; + } else { + return true; + } + } validateInputs() { let areInputsValid = true; let { softwareProductValidation, setGeneralInfo } = this.props; @@ -178,43 +243,57 @@ class VspValidationInputs extends Component { ); let isParameterValid = true; let errorText = ''; - if ( - parameter.type === 'text' && - parameter.metadata.choices - ) { - if ( - !parameter.isOptional && - !requestParameters[parameterName] - ) { - isParameterValid = false; - errorText = i18n('Field is required'); - } - } else if (parameter.type === 'text') { + if (!this.filterField(parameter)) { + // Not required any action + } else { if ( - !parameter.isOptional && - !requestParameters[parameterName] + (parameter.type === 'text' || + parameter.type === 'string') && + parameter.metadata.choices ) { - isParameterValid = false; - errorText = i18n('Field is required'); + if ( + !parameter.isOptional && + !requestParameters[parameterName] + ) { + isParameterValid = false; + errorText = i18n('Field is required'); + } } else if ( - (!parameter.isOptional && - !requestParameters[parameterName]) || - (parameter.metadata.maxLength && - requestParameters[parameterName].length > - parseInt(parameter.metadata.maxLength)) || - (parameter.metadata.minLength && - requestParameters[parameterName].length < - parseInt(parameter.metadata.minLength) && - requestParameters[parameterName].length > 0) + parameter.type === 'text' || + parameter.type === 'string' || + parameter.type === 'json' || + parameter.type === 'binary' ) { - isParameterValid = false; - errorText = i18n( - 'Value Should Be Minimum of {minLength} characters and a Maximum of {maxLength} characters', - { - minLength: parameter.metadata.minLength, - maxLength: parameter.metadata.maxLength - } - ); + if ( + !parameter.isOptional && + !requestParameters[parameterName] + ) { + isParameterValid = false; + errorText = i18n('Field is required'); + } else if ( + (!parameter.isOptional && + !requestParameters[parameterName]) || + (parameter.metadata.maxLength && + requestParameters[parameterName].length > + parseInt( + parameter.metadata.maxLength + )) || + (parameter.metadata.minLength && + requestParameters[parameterName].length < + parseInt( + parameter.metadata.minLength + ) && + requestParameters[parameterName].length > 0) + ) { + isParameterValid = false; + errorText = i18n( + 'Value Should Be Minimum of {minLength} characters and a Maximum of {maxLength} characters', + { + minLength: parameter.metadata.minLength, + maxLength: parameter.metadata.maxLength + } + ); + } } } generalInfo[testCaseName][ @@ -244,13 +323,22 @@ class VspValidationInputs extends Component { } = this.props; Object.keys(softwareProductValidation.testsRequest).forEach(key => { - tests.push(softwareProductValidation.testsRequest[key]); + var testReq = softwareProductValidation.testsRequest[key]; + this.removeParameterFromTest(testReq); + tests.push(testReq); }); if (this.validateInputs()) { - onTestSubmit(softwareProductId, version, status, tests); + var requestId = UUID.create() + .toString() + .split('-')[0]; + onTestSubmit(softwareProductId, version, status, tests, requestId); } } - + removeParameterFromTest(testReq) { + delete testReq.parameters['host-username']; + delete testReq.parameters['host-password']; + delete testReq.parameters['host-url']; + } prepareDataForVspInputs() { let { setTestsRequest } = this.props; let { @@ -279,7 +367,10 @@ class VspValidationInputs extends Component { isValid={true} onSubmit={() => this.performVSPTests()} isReadOnlyMode={false}> - <VspInputs {...this.prepareDataForVspInputs()} /> + <VspInputs + {...this.prepareDataForVspInputs()} + filterField={this.filterField} + /> <Button size="default" data-test-id="proceed-to-validation-results-btn" diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/setup/VspValidationSetupView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/setup/VspValidationSetupView.jsx index 012d50ac93..d1952bf7f2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/setup/VspValidationSetupView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validation/setup/VspValidationSetupView.jsx @@ -206,10 +206,14 @@ class ComplianceTests extends React.Component { let { complianceNodes, setComplianceChecked } = this.props; return ( <div className="validation-setup-checkbox-tree-section"> - <GridSection title={i18n('Compliance Checks')}> + <GridSection title={i18n('Available Tests')}> <GridItem colSpan={2}> <div className="validation-view-title"> - {complianceNodes[0] ? complianceNodes[0].value : ''} + {complianceNodes[0] && complianceNodes[0].value ? ( + complianceNodes[0].value + ) : ( + <br /> + )} </div> <div className="validation-setup-available-tests-section" @@ -237,9 +241,7 @@ class ComplianceTests extends React.Component { /> )} {complianceNodes.length === 0 && ( - <div> - {i18n('No Compliance Checks are Available')} - </div> + <div>{i18n('No Tests are Available')}</div> )} </div> </GridItem> @@ -247,7 +249,7 @@ class ComplianceTests extends React.Component { {complianceNodes.length > 0 && ( <div> <div className="validation-view-title"> - {i18n('Selected Compliance Tests')} + {i18n('Selected Tests')} </div> <div> <select diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResults.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResults.js index dffade7c9a..ed88dddc5a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResults.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResults.js @@ -15,14 +15,32 @@ */ import { connect } from 'react-redux'; import SoftwareProductValidationResultsView from './SoftwareProductValidationResultsView.jsx'; +import SoftwareProductValidationResultsViewActionHelper from './SoftwareProductValidationResultsViewActionHelper.js'; export const mapStateToProps = ({ softwareProduct }) => { + let { softwareProductValidationResult } = softwareProduct; let { softwareProductValidation } = softwareProduct; return { + softwareProductValidationResult, softwareProductValidation }; }; - -export default connect(mapStateToProps, null, null, { +export const mapActionsToProps = dispatch => { + return { + refreshValidationResults: (requestId, endPoints) => { + return SoftwareProductValidationResultsViewActionHelper.refreshValidationResults( + dispatch, + { requestId, endPoints } + ); + }, + updateDisplayTestResultData: testResultToDisplay => { + return SoftwareProductValidationResultsViewActionHelper.updateDisplayTestResultData( + dispatch, + { testResultToDisplay } + ); + } + }; +}; +export default connect(mapStateToProps, mapActionsToProps, null, { withRef: true })(SoftwareProductValidationResultsView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsView.jsx index 2c2cccd711..c5da4f6ca1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsView.jsx @@ -20,64 +20,48 @@ import { SVGIcon } from 'onap-ui-react'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import unCamelCasedString from 'nfvo-utils/unCamelCaseString.js'; - -const TestResultComponent = ({ tests }) => { - return ( - <div> - {tests.map((test, index) => { - let name = 'errorCircle'; - let color = 'warning'; - if ( - test.testResult && - test.testResult.toLowerCase() === 'pass' - ) { - color = 'positive'; - name = 'checkCircle'; - } else if ( - test.testResult && - test.testResult.toLowerCase() === 'fail' - ) { - name = 'exclamationTriangleFull'; - } - return ( - <li type="none" key={index}> - <SVGIcon - color={color} - name={name} - labelPosition="right" - /> - <span className="validation-results-test-result-label"> - {test.testName + - ' | ' + - test.testResult + - ' | ' + - test.notes} - </span> - </li> - ); - })} - </div> - ); -}; class SoftwareProductValidationResultsView extends React.Component { static propTypes = { - softwareProductValidation: PropTypes.object + softwareProductValidation: PropTypes.object, + refreshValidationResults: PropTypes.func }; constructor(props) { super(props); this.state = { vspId: this.props.softwareProductId, - versionNumber: this.props.version.name + versionNumber: this.props.version.name, + refreshValidationResults: this.props.refreshValidationResults, + vspTestResults: this.props.vspTestResults, + flatTestsMap: {}, + generalInfo: {} }; } + componentDidMount() { + this.configBasicTestData(); + } + componentDidUpdate() { + this.updateTestResultToDisplay(); + } + + prepareDataForCheckboxes(children, ftm) { + for (var val of children) { + if (val.children) { + this.prepareDataForCheckboxes(val.children, ftm); + } else if (val.tests) { + for (var test of val.tests) { + ftm[test.testCaseName] = test.description; + } + } + } + return ftm; + } getTitle(result) { - let { vspTestsMap } = this.props.softwareProductValidation; + let { flatTestsMap: vspTestsMap } = this.state; let title = vspTestsMap[result.testCaseName] - ? vspTestsMap[result.testCaseName].title + ? vspTestsMap[result.testCaseName].split(/\r?\n/)[0] : i18n('Unknown'); return i18n( 'Scenario: {scenario} | Title: {title} | Test Case: {testCaseName} | Status: {status}', @@ -90,19 +74,36 @@ class SoftwareProductValidationResultsView extends React.Component { ); } - renderJSON(result) { + renderJSON(result, indexKey) { + if (result.status === 'in-progress') { + return this.renderInprogress(i18n('Test is In-progress'), indexKey); + } else { + return ( + <li key={indexKey} type="none"> + <textarea + disabled={true} + className="validation-results-test-result-json" + value={JSON.stringify(result, null, 2)} + /> + </li> + ); + } + } + renderInprogress(result, indexKey) { return ( - <li type="none"> - <textarea - disabled={true} - className="validation-results-test-result-json" - value={JSON.stringify(result, null, 2)} + <li key={indexKey} type="none"> + <SVGIcon + color="warning" + name="exclamationTriangleLine" + labelPosition="right" /> + <span className="validation-results-test-result-label"> + {result} + </span> </li> ); } - - renderError(result) { + renderError(result, indexKey) { if (Array.isArray(result)) { return result.map((parameter, index) => { return ( @@ -120,95 +121,60 @@ class SoftwareProductValidationResultsView extends React.Component { </li> ); }); - } else { + } else if ( + typeof result === 'string' || + result.hasOwnProperty('code') || + result.hasOwnProperty('advice') || + result.hasOwnProperty('message') || + result.hasOwnProperty('error') + ) { + result = + result instanceof Object && result.error instanceof Object + ? result.error + : result; return ( - <li type="none"> + <li key={indexKey} type="none"> <SVGIcon color="negative" name="errorCircle" labelPosition="right" /> <span className="validation-results-test-result-label"> - {(result.code || '') + - ' | ' + - (result.advice || result.message)} + {typeof result === 'string' + ? result + : (result.code || '') + + ' | ' + + (result.advice || result.message || result.error)} </span> </li> ); - } - } - - renderResults(result) { - if (typeof result === 'string' || result instanceof String) { + } else { return ( - <div> - <SVGIcon - color="warning" - name="errorCircle" - labelPosition="right" - /> - <span className="validation-results-test-result-label"> - {result} - </span> - </div> + <Accordion key={indexKey} defaultExpanded> + {this.renderJSON(result)} + </Accordion> ); } - return Object.keys(result).map((key, index) => { - let title = unCamelCasedString(key); - if ( - typeof result[key] === 'string' || - result[key] instanceof String - ) { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title} - key={index}> - {this.renderString(result[key])} - </Accordion> - ); - } else if (Array.isArray(result[key])) { - if (result[key].length > 0) { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title} - key={index}> - <TestResultComponent tests={result[key]} /> - </Accordion> - ); - } else { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title} - key={index}> - {i18n('{title} results are not available', { - title: title - })} - </Accordion> - ); - } - } else { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title} - key={index}> - {this.renderJSON(result[key])} - </Accordion> - ); - } - }); } - renderString(result) { + renderResults(result, indexKey) { return ( - <li type="none"> + <li key={indexKey} type="none"> + <SVGIcon + color="positive" + name="checkCircle" + labelPosition="right" + /> + <span className="validation-results-test-result-label"> + {result} + </span> + </li> + ); + } + + renderString(result, indexKey) { + return ( + <li key={indexKey} type="none"> <textarea type="textarea" disabled={true} @@ -219,92 +185,191 @@ class SoftwareProductValidationResultsView extends React.Component { ); } - buildSubAccordions(result) { + buildSubAccordions(result, indexKey) { let results = result.results; if (!results) { return ( <Accordion + key={indexKey} defaultExpanded dataTestId="vsp-test-no-results" title={this.getTitle(result)}> - {this.renderJSON(result)} + {this.renderJSON(result, indexKey)} </Accordion> ); } else if (typeof results === 'string' || results instanceof String) { return ( <Accordion + key={indexKey} defaultExpanded dataTestId="vsp-test-string-results" title={this.getTitle(result)}> - {this.renderString(results)} + {this.renderString(results, indexKey)} </Accordion> ); } else { return ( <Accordion + key={indexKey} defaultExpanded dataTestId="vsp-test-object-results" title={this.getTitle(result)}> {Object.keys(results).length === 0 ? this.renderString( - i18n('{title} results are not available', { - title: 'Test' - }) + i18n( + '{title} results are not available', + { + title: 'Test' + }, + indexKey + ) ) - : Object.keys(results).map(key => { - if (key === 'errors' || key === 'error') { - return this.renderError(results[key]); - } else if (key === 'testResults') { - return this.renderResults(results[key]); - } else { - let title = unCamelCasedString(key); - if (results[key] instanceof Object) { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title}> - {this.renderJSON(results[key])} - </Accordion> - ); - } else { - return ( - <Accordion - defaultExpanded - dataTestId={title} - title={title}> - {this.renderString(results[key])} - </Accordion> - ); - } - } - })} + : Array.isArray(results) + ? Object.keys(results).map((key, indexKey) => { + if (Object.keys(results[key]).length === 0) { + return this.renderResults( + result.testCaseName + + ' ' + + i18n('has passed all checks'), + indexKey + ); + } else { + return this.renderError( + results[key], + indexKey + ); + } + }) + : this.renderError(results, indexKey)} </Accordion> ); } } - + refreshValidationResult(thisObj) { + let { refreshValidationResults } = thisObj.props; + var testResultKey = this.props.softwareProductValidationResult + .testResultKeys[this.state.vspId + this.state.versionNumber]; + refreshValidationResults( + testResultKey.requestId, + testResultKey.endPoints + ); + delete this.props.softwareProductValidation.vspTestResults; + } + configBasicTestData() { + let { + softwareProductValidationResult, + softwareProductValidation + } = this.props; + if ( + softwareProductValidationResult.vspChecks !== undefined && + softwareProductValidationResult.vspChecks.children !== undefined + ) { + var ftm = this.prepareDataForCheckboxes( + this.props.softwareProductValidationResult.vspChecks.children, + {} + ); + this.setState({ + flatTestsMap: ftm + }); + } + if (softwareProductValidation.testResultKeys) { + if (!this.props.softwareProductValidationResult.testResultKeys) { + this.props.softwareProductValidationResult.testResultKeys = {}; + } + this.props.softwareProductValidationResult.testResultKeys[ + this.state.vspId + this.state.versionNumber + ] = + softwareProductValidation.testResultKeys; + delete this.props.softwareProductValidation.testResultKeys; + } + } + updateTestResultToDisplay() { + if (this.props.softwareProductValidation.vspTestResults) { + let { updateDisplayTestResultData } = this.props; + var testResultToDisplay = this.props.softwareProductValidationResult + .testResultToDisplay; + testResultToDisplay = testResultToDisplay + ? testResultToDisplay + : {}; + testResultToDisplay[ + this.state.vspId + this.state.versionNumber + ] = this.props.softwareProductValidation.vspTestResults; + updateDisplayTestResultData(testResultToDisplay); + delete this.props.softwareProductValidation.vspTestResults; + } else if (this.props.softwareProductValidationResult.vspTestResults) { + let { updateDisplayTestResultData } = this.props; + var testResultToDisplay = this.props.softwareProductValidationResult + .testResultToDisplay + ? this.props.softwareProductValidationResult.testResultToDisplay + : {}; + testResultToDisplay[ + this.state.vspId + this.state.versionNumber + ] = this.props.softwareProductValidationResult.vspTestResults; + updateDisplayTestResultData(testResultToDisplay); + delete this.props.softwareProductValidationResult.vspTestResults; + } + } render() { - let results = this.props.softwareProductValidation.vspTestResults || []; - if (results.length > 0) { + let testResultToDisplay = this.props.softwareProductValidationResult + .testResultToDisplay; + let results = testResultToDisplay + ? testResultToDisplay[this.state.vspId + this.state.versionNumber] + : null; + if (!results) { return ( - <GridSection title={i18n('Validation Results')}> - <GridItem colSpan={10}> - <Accordion - defaultExpanded - dataTestId="vsp-validation-test-result" - title={i18n('Test Results')}> - {results.map(row => this.buildSubAccordions(row))} - </Accordion> - </GridItem> + <GridSection title={i18n('Test Results')}> + <h4>{i18n('No Test Performed')}</h4> </GridSection> ); + } else if (results.length > 0) { + return ( + <div> + <div + onClick={() => this.refreshValidationResult(this)} + data-test-id="vsp-validation-refresh-btn" + className={'vcp-validation-refresh-btn'}> + <SVGIcon + label="Refresh" + labelPosition="left" + color="" + iconClassName="vcp-validation-refresh-icon" + name="versionControllerSync" + /> + </div> + <GridSection title={i18n('Test Results')}> + <GridItem colSpan={10}> + <Accordion + defaultExpanded + dataTestId="vsp-validation-test-result" + title={i18n('Test Results')}> + {results.map((row, index) => + this.buildSubAccordions(row, index) + )} + </Accordion> + </GridItem> + </GridSection> + </div> + ); } else { return ( - <GridSection title={i18n('Validation Results')}> - <h4>{i18n('No Validation Checks Performed')}</h4> - </GridSection> + <div> + <div + onClick={() => this.refreshValidationResult(this)} + data-test-id="vsp-validation-refresh-btn" + className={'vcp-validation-refresh-btn'}> + <SVGIcon + label="Refresh" + labelPosition="left" + color="" + iconClassName="vcp-validation-refresh-icon" + name="versionControllerSync" + /> + </div> + <GridSection title={i18n('Test Results')}> + <h4>{i18n('No Test Result Available')}</h4> + </GridSection> + </div> ); } } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewActionHelper.js new file mode 100644 index 0000000000..4da8b9b30d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewActionHelper.js @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2019 Vodafone Group + * + * 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. + */ +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import { actionTypes } from './SoftwareProductValidationResultsViewConstants.js'; + +function encodeResultQueryData(requestId, endPoints) { + const query = []; + query.push('requestId=' + requestId); + endPoints.forEach(endPoint => { + query.push('endPoint=' + encodeURIComponent(endPoint)); + }); + + return query.join('&'); +} +function fetchVspValidationResults(requestId, endPoints) { + const restPrefix = Configuration.get('restPrefix'); + const requestQuery = encodeResultQueryData(requestId, endPoints); + return RestAPIUtil.fetch( + `${restPrefix}/v1.0/externaltesting/executions?${requestQuery}` + ); +} +function fetchVspChecks() { + const restPrefix = Configuration.get('restPrefix'); + return RestAPIUtil.fetch(`${restPrefix}/v1.0/externaltesting/testcasetree`); +} +const SoftwareProductValidationResultsViewActionHelper = { + refreshValidationResults(dispatch, { requestId, endPoints }) { + return new Promise((resolve, reject) => { + fetchVspValidationResults(requestId, endPoints) + .then(response => { + dispatch({ + type: actionTypes.FETCH_VSP_RESULT, + vspTestResults: response + }); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + }, + fetchVspChecks(dispatch) { + return new Promise((resolve, reject) => { + fetchVspChecks() + .then(response => { + dispatch({ + type: actionTypes.FETCH_VSP_CHECKS, + vspChecks: response + }); + resolve(response); + }) + .catch(error => { + reject(error); + }); + }); + }, + updateDisplayTestResultData(dispatch, { testResultToDisplay }) { + dispatch({ + type: actionTypes.UPDATE_DISPLAY_TEST_RESULT_DATA, + testResultToDisplay: testResultToDisplay + }); + } +}; + +export default SoftwareProductValidationResultsViewActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewConstants.js new file mode 100644 index 0000000000..22fcb12131 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewConstants.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2019 Vodafone Group + * + * 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. + */ +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror( + { + FETCH_VSP_RESULT: null, + FETCH_VSP_CHECKS: null, + UPDATE_DISPLAY_TEST_RESULT_DATA: null + }, + 'SoftwareProductValidationResults' +); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewReducer.js new file mode 100644 index 0000000000..99bf68f723 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/validationResults/SoftwareProductValidationResultsViewReducer.js @@ -0,0 +1,27 @@ +import { actionTypes } from './SoftwareProductValidationResultsViewConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.FETCH_VSP_RESULT: { + return { + ...state, + vspTestResults: action.vspTestResults + }; + } + case actionTypes.FETCH_VSP_CHECKS: { + return { + ...state, + vspChecks: action.vspChecks + }; + } + case actionTypes.UPDATE_DISPLAY_TEST_RESULT_DATA: { + return { + ...state, + vspTestResults: null, + testResultToDisplay: action.testResultToDisplay + }; + } + default: + return state; + } +}; |