summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandre.schmid <andre.schmid@est.tech>2022-01-25 19:38:32 +0000
committerMichael Morris <michael.morris@est.tech>2022-01-31 15:23:21 +0000
commit4594cba0c53461bc1a273458e0a7a314da6bfb68 (patch)
treec78010c789d726aa72ee8591ab12720b72d1c675
parent99b7fb519806870b3c84e9e1ac0ac2f59320a6b0 (diff)
Obtain and control VSP package upload status
Obtain the upload status and control the upload from the frontend perspective. Change-Id: Idcc921cf592efea33df35c557afcfae827af3a39 Issue-ID: SDC-3862 Signed-off-by: andre.schmid <andre.schmid@est.tech>
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java5
-rw-r--r--openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java6
-rw-r--r--openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java2
-rw-r--r--openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java15
-rw-r--r--openecomp-ui/README.md10
-rw-r--r--openecomp-ui/package.json2
-rw-r--r--openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss4
-rw-r--r--openecomp-ui/src/nfvo-components/loader/LoaderReducer.js4
-rw-r--r--openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx23
-rw-r--r--openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js2
-rw-r--r--openecomp-ui/src/nfvo-utils/RestAPIUtil.js74
-rw-r--r--openecomp-ui/src/nfvo-utils/i18n/en.json8
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js44
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js53
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx195
-rw-r--r--openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/VspUploadStatus.js73
-rw-r--r--openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js16
17 files changed, 413 insertions, 123 deletions
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
index 6615447c6f..b51583980d 100644
--- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImpl.java
@@ -152,18 +152,21 @@ public class OrchestrationTemplateCandidateImpl implements OrchestrationTemplate
fileToUploadBytes = fileToUpload.getObject(byte[].class);
}
-
vspUploadStatus = orchestrationTemplateCandidateUploadManager.putUploadInValidation(vspId, versionId, user);
final var onboardingPackageProcessor =
new OnboardingPackageProcessor(filename, fileToUploadBytes, new CnfPackageValidator(), artifactInfo);
final ErrorMessage[] errorMessages = onboardingPackageProcessor.getErrorMessages().toArray(new ErrorMessage[0]);
if (onboardingPackageProcessor.hasErrors()) {
+ orchestrationTemplateCandidateUploadManager
+ .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
return Response.status(NOT_ACCEPTABLE).entity(buildUploadResponseWithError(errorMessages)).build();
}
final var onboardPackageInfo = onboardingPackageProcessor.getOnboardPackageInfo().orElse(null);
if (onboardPackageInfo == null) {
final UploadFileResponseDto uploadFileResponseDto = buildUploadResponseWithError(
new ErrorMessage(ErrorLevel.ERROR, PACKAGE_PROCESS_ERROR.formatMessage(filename)));
+ orchestrationTemplateCandidateUploadManager
+ .putUploadAsFinished(vspId, versionId, vspUploadStatus.getLockId(), VspUploadStatus.ERROR, user);
return Response.ok(uploadFileResponseDto).build();
}
final var version = new Version(versionId);
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
index 758505f583..6c21cc471e 100644
--- a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
+++ b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vendor-software-products-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/OrchestrationTemplateCandidateImplTest.java
@@ -223,8 +223,12 @@ class OrchestrationTemplateCandidateImplTest {
@Test
void uploadSignNotValidTest() throws IOException {
+ //given
+ when(orchestrationTemplateCandidateUploadManager.putUploadInValidation(candidateId, versionId, user)).thenReturn(new VspUploadStatusDto());
+ //when
Response response = orchestrationTemplateCandidate
- .upload("1", "1", mockAttachment("filename.zip", null), user);
+ .upload(candidateId, versionId, mockAttachment("filename.zip", null), user);
+ //then
assertEquals(Status.NOT_ACCEPTABLE.getStatusCode(), response.getStatus());
assertFalse(((UploadFileResponseDto) response.getEntity()).getErrors().isEmpty());
}
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java
index 558016c9af..7b0da51c05 100644
--- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java
+++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoIml.java
@@ -91,7 +91,7 @@ public class VspUploadStatusRecordDaoIml implements VspUploadStatusRecordDao {
public Optional<VspUploadStatusRecord> findLatest(final String vspId, final String vspVersionId) {
final List<VspUploadStatusRecord> vspUploadStatusRecordList = accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId).all();
vspUploadStatusRecordList.sort(Comparator.comparing(VspUploadStatusRecord::getCreated).reversed());
- return Optional.ofNullable(vspUploadStatusRecordList.get(0));
+ return vspUploadStatusRecordList.isEmpty() ? Optional.empty() : Optional.ofNullable(vspUploadStatusRecordList.get(0));
}
}
diff --git a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java
index cd0bc1cd1e..f17d250a32 100644
--- a/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java
+++ b/openecomp-be/lib/openecomp-sdc-vendor-software-product-lib/openecomp-sdc-vendor-software-product-core/src/test/java/org/openecomp/sdc/vendorsoftwareproduct/dao/impl/VspUploadStatusRecordDaoImlTest.java
@@ -130,4 +130,19 @@ class VspUploadStatusRecordDaoImlTest {
assertEquals(mostRecentVspUploadStatus, vspUploadStatusOptional.get());
}
+ @Test
+ void findLatest_noEntryFoundTest() {
+ //given
+ final String vspId = "vspId";
+ final String vspVersionId = "vspVersionId";
+ final Result<VspUploadStatusRecord> resultMock = mock(Result.class);
+ when(resultMock.all()).thenReturn(new ArrayList<>());
+
+ when(accessor.findAllByVspIdAndVspVersionId(vspId, vspVersionId)).thenReturn(resultMock);
+ //when
+ final Optional<VspUploadStatusRecord> vspUploadStatusOptional = packageUploadManagerDaoIml.findLatest(vspId, vspVersionId);
+ //then
+ assertTrue(vspUploadStatusOptional.isEmpty());
+ }
+
} \ No newline at end of file
diff --git a/openecomp-ui/README.md b/openecomp-ui/README.md
index c270802744..a41aa27e37 100644
--- a/openecomp-ui/README.md
+++ b/openecomp-ui/README.md
@@ -35,8 +35,8 @@ install gulp by running the following command `npm install --global gulp-cli`
* your favorite UI will wait for you at: `http://localhost:9000/sdc1/#!/onboardVendor`
## Troubleshooting
-Problem | Why is this happening | Solution
-------- | --------------------- | --------
-Build (npm install) error | npm/node_modules cache | If having problems with the compilation of dox-sequence-diagram-ui and openecomp-ui, delete the node_modules and package-lock.json in each respective projects folder.
-npm cannot reach destination | proxy | When within managed network, you should set your proxy to NPM as the following: <br> `npm config set proxy http://<host>:<port>` <br> `npm config set https-proxy http://<host>:<port>`
-git protocol is blocked and cannot connect | managed network rules for protocols | When within managed network, you should set globally that when git protocol is used, then it will be replaced with "https" <br> `git config --global url."https://".insteadOf git://`
+| Problem | Why is this happening | Solution |
+|--------------------------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| Build (npm install) error | npm/node_modules cache | If having problems with the compilation of dox-sequence-diagram-ui and openecomp-ui, delete the node_modules and package-lock.json in each respective projects folder. |
+| npm cannot reach destination | proxy | When within managed network, you should set your proxy to NPM as the following: <br> `npm config set proxy http://<host>:<port>` <br> `npm config set https-proxy http://<host>:<port>` |
+| git protocol is blocked and cannot connect | managed network rules for protocols | When within managed network, you should set globally that when git protocol is used, then it will be replaced with "https" <br> `git config --global url."https://".insteadOf git://` |
diff --git a/openecomp-ui/package.json b/openecomp-ui/package.json
index e19b0b1c71..96e7c43837 100644
--- a/openecomp-ui/package.json
+++ b/openecomp-ui/package.json
@@ -18,7 +18,7 @@
},
"dependencies": {
"attr-accept": "^1.1.0",
- "axios": "^0.16.2",
+ "axios": "^0.25.0",
"classnames": "^2.2.5",
"core-js": "^2.4.0",
"d3": "^4.10.0",
diff --git a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
index c1cf3cf778..a6276275d4 100644
--- a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
+++ b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss
@@ -199,6 +199,10 @@
color: $blue;
@extend .body-1-semibold;
}
+ .upload-status-text {
+ color: $blue;
+ @extend .body-1-semibold;
+ }
.or-text {
margin-top: 10px;
margin-bottom: 10px;
diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
index 3f9eb17db3..4222c3dac6 100644
--- a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
+++ b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js
@@ -32,7 +32,9 @@ export default (
isLoading: true
};
case actionTypes.RECEIVE_RESPONSE:
- fetchingRequests--;
+ if (fetchingRequests > 0) {
+ fetchingRequests--;
+ }
newArray = state.currentlyFetching.filter(item => {
return item !== action.url;
diff --git a/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx b/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx
index 2c82c2be6c..32e3a3e3f2 100644
--- a/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx
+++ b/openecomp-ui/src/nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx
@@ -50,22 +50,27 @@ class VnfRepositorySearchBox extends Component {
dataTestId,
isReadOnlyMode
} = this.props;
- let showVNF = Configuration.get('showBrowseVNF');
+ const showVNF = Configuration.get('showBrowseVNF');
return (
- <div className={`${className}${isReadOnlyMode ? ' disabled' : ''}`}>
+ <div
+ className={`${className}${isReadOnlyMode ? ' disabled' : ''}${
+ showVNF ? ' showVnf' : ''
+ }`}>
<DraggableUploadFileBox
dataTestId={dataTestId}
isReadOnlyMode={isReadOnlyMode}
className={'upload'}
onClick={onClick}
/>
-
- <div className={`${'verticalLine'}${showVNF ? '' : ' hide'}`} />
-
- <VNFBrowse
- onBrowseVNF={onBrowseVNF}
- isReadOnlyMode={isReadOnlyMode}
- />
+ {showVNF && (
+ <div className={`verticalLine${showVNF ? '' : ' hide'}`} />
+ )}
+ {showVNF && (
+ <VNFBrowse
+ onBrowseVNF={onBrowseVNF}
+ isReadOnlyMode={isReadOnlyMode}
+ />
+ )}
</div>
);
}
diff --git a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
index 5c55855027..e7d3f8a85c 100644
--- a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
+++ b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
@@ -64,7 +64,7 @@ function parseCatalogExceptionObject(responseJSON) {
return { title, msg };
}
-var errorResponseHandler = error => {
+const errorResponseHandler = error => {
let errorData;
if (error.data) {
errorData = parseCatalogExceptionObject(error.data);
diff --git a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
index 03908d8203..97d3847350 100644
--- a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
+++ b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
@@ -77,55 +77,69 @@ class RestAPIUtil {
handleRequest(url, type, options = {}, data = {}) {
applySecurity(options, data);
- let config = {
+ const config = {
method: type,
url: url,
headers: options.headers,
data: data
};
- store.dispatch({ type: LoaderConstants.SEND_REQUEST, url: url });
+ if (options.validateStatus) {
+ config.validateStatus = options.validateStatus;
+ }
+
+ if (options.onUploadProgress) {
+ config.onUploadProgress = options.onUploadProgress;
+ }
+
+ if (!options.noLoading) {
+ store.dispatch({ type: LoaderConstants.SEND_REQUEST, url: url });
+ }
if (options.dataType === BINARY) {
config.responseType = 'arraybuffer';
return axios(config)
.then(result => {
- store.dispatch({
- type: LoaderConstants.RECEIVE_RESPONSE,
- url: result.config.url
- });
+ if (!options.noLoading) {
+ store.dispatch({
+ type: LoaderConstants.RECEIVE_RESPONSE,
+ url: result.config.url
+ });
+ }
+
return {
blob: new Blob([result.data]),
headers: result.headers
};
})
.catch(error => {
- store.dispatch({
- type: LoaderConstants.RECEIVE_RESPONSE,
- url: error.config.url
- });
- errorResponseHandler(error.response);
- });
- } else {
- return axios(config)
- .then(result => {
- store.dispatch({
- type: LoaderConstants.RECEIVE_RESPONSE,
- url: result.config.url
- });
- handleSuccess(result.headers, result.config.headers);
- return result.data;
- })
- .catch(error => {
- store.dispatch({
- type: LoaderConstants.RECEIVE_RESPONSE,
- url: error.config.url
- });
+ if (!options.noLoading) {
+ store.dispatch({
+ type: LoaderConstants.RECEIVE_RESPONSE,
+ url: error.config.url
+ });
+ }
errorResponseHandler(error.response);
- return Promise.reject({
- responseJSON: error.response.data
- });
});
}
+ return axios(config)
+ .then(result => {
+ store.dispatch({
+ type: LoaderConstants.RECEIVE_RESPONSE,
+ url: result.config.url
+ });
+ handleSuccess(result.headers, result.config.headers);
+ return result.data;
+ })
+ .catch(error => {
+ store.dispatch({
+ type: LoaderConstants.RECEIVE_RESPONSE,
+ url: error.config.url
+ });
+ errorResponseHandler(error.response);
+ return Promise.reject({
+ responseJSON: error.response.data
+ });
+ });
}
fetch(url, options) {
diff --git a/openecomp-ui/src/nfvo-utils/i18n/en.json b/openecomp-ui/src/nfvo-utils/i18n/en.json
index 7a2e66a4b3..ada011f7c3 100644
--- a/openecomp-ui/src/nfvo-utils/i18n/en.json
+++ b/openecomp-ui/src/nfvo-utils/i18n/en.json
@@ -662,6 +662,10 @@
"Unknown": "Unknown",
"No Test Result Available": "No Test Result Available",
"Test is In-progress": "Test is In-progress",
- "has passed all checks": "has passed all checks"
-
+ "has passed all checks": "has passed all checks",
+ "upload.status.uploading": "Package upload is in progress",
+ "upload.status.validating": "Package is in validation",
+ "upload.status.processing": "Package is being processed",
+ "upload.status.success": "Package was successfully uploaded",
+ "upload.status.error": "Package upload resulted in error"
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
index 5c82c70830..3364edfe11 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js
@@ -112,12 +112,19 @@ function getModelUrl() {
return `${restCatalogPrefix}/v1/catalog/model?modelType=normative`;
}
-function uploadFile(vspId, formData, version) {
+function uploadFile(vspId, formData, version, onUploadProgress = undefined) {
+ const options = {
+ noLoading: true
+ };
+ if (onUploadProgress) {
+ options.onUploadProgress = onUploadProgress;
+ }
return RestAPIUtil.post(
`${baseUrl()}${vspId}/versions/${
version.id
}/orchestration-template-candidate`,
- formData
+ formData,
+ options
);
}
@@ -346,6 +353,19 @@ const SoftwareProductActionHelper = {
);
},
+ fetchUploadStatus(vspId, versionId) {
+ const options = {
+ validateStatus: function(status) {
+ return status < 400 || status === 404;
+ },
+ noLoading: true
+ };
+ return RestAPIUtil.get(
+ `${baseUrl()}${vspId}/versions/${versionId}/orchestration-template-candidate/upload`,
+ options
+ );
+ },
+
loadSoftwareProductAssociatedData(dispatch) {
fetchSoftwareProductCategories(dispatch);
fetchModelList(dispatch);
@@ -435,15 +455,27 @@ const SoftwareProductActionHelper = {
uploadFile(
dispatch,
- { softwareProductId, formData, failedNotificationTitle, version }
+ {
+ softwareProductId,
+ formData,
+ failedNotificationTitle,
+ version,
+ onUploadProgress = undefined
+ }
) {
dispatch({
type: HeatSetupActions.FILL_HEAT_SETUP_CACHE,
payload: {}
});
- displayTimingValidationInfo(dispatch);
- Promise.resolve()
- .then(() => uploadFile(softwareProductId, formData, version))
+ return Promise.resolve()
+ .then(() =>
+ uploadFile(
+ softwareProductId,
+ formData,
+ version,
+ onUploadProgress
+ )
+ )
.then(response => {
if (response.status === 'Success') {
dispatch({
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
index fa136f2f1b..4b4c2fa86b 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js
@@ -109,15 +109,40 @@ const mapActionsToProps = (dispatch, { version }) => {
screenType: screenTypes.SOFTWARE_PRODUCT,
props: { softwareProductId, version }
}),
- onUpload: (softwareProductId, formData) =>
+ onUpload: (
+ softwareProductId,
+ formData,
+ onUploadStart = () => {
+ // do nothing by default
+ },
+ onUploadProgress = undefined,
+ onUploadFinished = () => {
+ // do nothing by default
+ }
+ ) => {
SoftwareProductActionHelper.uploadFile(dispatch, {
softwareProductId,
formData,
failedNotificationTitle: i18n('Upload validation failed'),
- version
- }),
+ version,
+ onUploadProgress
+ }).finally(() => {
+ onUploadFinished();
+ });
+ onUploadStart();
+ },
- onUploadConfirmation: (softwareProductId, formData) =>
+ onUploadConfirmation: (
+ softwareProductId,
+ formData,
+ onUploadStart = () => {
+ // do nothing by default
+ },
+ onUploadProgress = undefined,
+ onUploadFinished = () => {
+ // do nothing by default
+ }
+ ) =>
dispatch({
type: modalActionTypes.GLOBAL_MODAL_WARNING,
data: {
@@ -126,15 +151,21 @@ const mapActionsToProps = (dispatch, { version }) => {
),
confirmationButtonText: i18n('Continue'),
title: i18n('Warning'),
- onConfirmed: () =>
+ onConfirmed: () => {
SoftwareProductActionHelper.uploadFile(dispatch, {
softwareProductId,
formData,
failedNotificationTitle: i18n(
'Upload validation failed'
),
- version
- }),
+ version,
+ onUploadProgress
+ }).finally(value => {
+ console.log('upload finished', value);
+ onUploadFinished();
+ });
+ onUploadStart();
+ },
onDeclined: () =>
dispatch({
type: modalActionTypes.GLOBAL_MODAL_CLOSE
@@ -153,6 +184,14 @@ const mapActionsToProps = (dispatch, { version }) => {
)
}
}),
+
+ fetchUploadStatus: softwareProductId => {
+ return SoftwareProductActionHelper.fetchUploadStatus(
+ softwareProductId,
+ version.id
+ );
+ },
+
onComponentSelect: ({ id: softwareProductId, componentId }) =>
ScreensHelper.loadScreen(dispatch, {
screen: screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL,
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
index 5f208345f7..c560a73db3 100644
--- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx
@@ -20,12 +20,12 @@ import classnames from 'classnames';
import Dropzone from 'react-dropzone';
import i18n from 'nfvo-utils/i18n/i18n.js';
-import Configuration from 'sdc-app/config/Configuration.js';
-import DraggableUploadFileBox from 'nfvo-components/fileupload/DraggableUploadFileBox.jsx';
import VnfRepositorySearchBox from 'nfvo-components/vnfMarketPlace/VnfRepositorySearchBox.jsx';
import { SVGIcon } from 'onap-ui-react';
import SoftwareProductComponentsList from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js';
+import VspUploadStatus from 'sdc-app/onboarding/softwareProduct/landingPage/VspUploadStatus';
+import ProgressBar from 'react-bootstrap/lib/ProgressBar';
const SoftwareProductPropType = PropTypes.shape({
name: PropTypes.string,
@@ -52,7 +52,10 @@ class SoftwareProductLandingPageView extends React.Component {
state = {
fileName: '',
dragging: false,
- files: []
+ uploadStatus: {},
+ files: [],
+ uploadProgress: 0,
+ showProgressBar: false
};
constructor(props) {
@@ -69,11 +72,13 @@ class SoftwareProductLandingPageView extends React.Component {
version: PropTypes.object,
onLicenseChange: PropTypes.func,
onUpload: PropTypes.func,
+ fetchUploadStatus: PropTypes.func,
onUploadConfirmation: PropTypes.func,
onInvalidFileSizeUpload: PropTypes.func,
onComponentSelect: PropTypes.func,
onAddComponent: PropTypes.func
};
+
componentDidMount() {
const {
onCandidateInProcess,
@@ -83,6 +88,41 @@ class SoftwareProductLandingPageView extends React.Component {
if (currentSoftwareProduct.candidateOnboardingOrigin && !isCertified) {
onCandidateInProcess(currentSoftwareProduct.id);
}
+ this.keepCheckingUploadStatus();
+ }
+
+ componentWillUnmount() {
+ this.stopUploadStatusChecking();
+ }
+
+ keepCheckingUploadStatus(initialDelayInMs = 0, updatePeriodInMs = 10000) {
+ this.stopUploadStatusChecking();
+ setTimeout(() => this.updateUploadStatus(), initialDelayInMs);
+ this.uploadStatusInterval = setInterval(
+ () => this.updateUploadStatus(),
+ updatePeriodInMs
+ );
+ }
+
+ stopUploadStatusChecking() {
+ clearInterval(this.uploadStatusInterval);
+ }
+
+ updateUploadStatus() {
+ const currentVspId = this.props.currentSoftwareProduct.id;
+ this.props
+ .fetchUploadStatus(currentVspId)
+ .then(uploadStatusResponse => {
+ const vspUploadStatus = new VspUploadStatus(
+ uploadStatusResponse
+ );
+ this.setState({
+ uploadStatus: vspUploadStatus
+ });
+ })
+ .catch(error =>
+ console.error('Could not retrieve upload status', error)
+ );
}
licenceChange = (e, currentSoftwareProduct, onLicenseChange) => {
@@ -93,7 +133,7 @@ class SoftwareProductLandingPageView extends React.Component {
};
getExternalLicenceFeatureState() {
- var licenseFeature = this.props.features.find(
+ const licenseFeature = this.props.features.find(
feature => feature.name === 'EXTERNAL_LICENSE'
);
return licenseFeature ? licenseFeature.active : true;
@@ -136,10 +176,11 @@ class SoftwareProductLandingPageView extends React.Component {
onLicenseChange={onLicenseChange}
externalLicenceEnabled={this.getExternalLicenceFeatureState()}
/>
- {this.renderProductDetails(
- isManual,
- isReadOnlyMode
- )}
+ <div className="details-panel">
+ {this.renderProductAttachments(
+ isReadOnlyMode
+ )}
+ </div>
</div>
</div>
</div>
@@ -155,56 +196,50 @@ class SoftwareProductLandingPageView extends React.Component {
}
}
- renderProductDetails(isManual, isReadOnlyMode) {
+ isUploadInProgress() {
+ return (
+ this.state.uploadStatus.complete !== undefined &&
+ !this.state.uploadStatus.complete
+ );
+ }
+
+ renderProductAttachments(isReadOnlyMode) {
let { onBrowseVNF, currentSoftwareProduct } = this.props;
- if (Configuration.get('showBrowseVNF')) {
- return (
- <div className="details-panel">
- {!isManual && (
- <div>
- <div className="software-product-landing-view-heading-title">
- {i18n('Software Product Attachments')}
- </div>
- <VnfRepositorySearchBox
- dataTestId="upload-btn"
- isReadOnlyMode={isReadOnlyMode}
- className={classnames(
- 'software-product-landing-view-top-block-col-upl showVnf',
- { disabled: isReadOnlyMode }
- )}
- onClick={() => this.refs.fileInput.open()}
- onBrowseVNF={() =>
- onBrowseVNF(currentSoftwareProduct)
- }
- />
- </div>
- )}
- </div>
- );
- } else {
+ if (this.isUploadInProgress()) {
return (
- <div className="details-panel">
- {!isManual && (
- <div>
- <div className="software-product-landing-view-heading-title">
- {i18n('Software Product Attachments')}
- </div>
- <DraggableUploadFileBox
- dataTestId="upload-btn"
- isReadOnlyMode={isReadOnlyMode}
- className={classnames(
- 'software-product-landing-view-top-block-col-upl',
- { disabled: isReadOnlyMode }
- )}
- onClick={() => this.refs.fileInput.open()}
- onBrowseVNF={() => onBrowseVNF()}
- />
+ <div>
+ <div className="software-product-landing-view-heading-title">
+ {i18n('Software Product Attachments')}
+ </div>
+ <div className="software-product-landing-view-top-block-col-upl ">
+ <div className="upload-status-text">
+ {this.state.uploadStatus.statusToString()}
+ {this.state.showProgressBar && (
+ <ProgressBar now={this.state.uploadProgress} />
+ )}
</div>
- )}
+ </div>
</div>
);
}
+ return (
+ <div>
+ <div className="software-product-landing-view-heading-title">
+ {i18n('Software Product Attachments')}
+ </div>
+ <VnfRepositorySearchBox
+ dataTestId="upload-btn"
+ isReadOnlyMode={isReadOnlyMode}
+ className={classnames(
+ 'software-product-landing-view-top-block-col-upl',
+ { disabled: isReadOnlyMode }
+ )}
+ onClick={() => this.refs.fileInput.open()}
+ onBrowseVNF={() => onBrowseVNF(currentSoftwareProduct)}
+ />
+ </div>
+ );
}
handleImportSubmit(files, isReadOnlyMode, isManual) {
@@ -226,6 +261,48 @@ class SoftwareProductLandingPageView extends React.Component {
}
}
+ onUploadStart = () => {
+ this.stopUploadStatusChecking();
+ this.showProgressBar();
+ };
+
+ onUploadProgress = progressEvent => {
+ const vspUploadStatus = new VspUploadStatus({
+ status: VspUploadStatus.UPLOADING,
+ complete: false
+ });
+ this.setState({
+ uploadStatus: vspUploadStatus
+ });
+ const percentCompleted = Math.round(
+ progressEvent.loaded * 100 / progressEvent.total
+ );
+ if (percentCompleted === 100) {
+ this.keepCheckingUploadStatus(5000);
+ this.resetUploadProgress(2000);
+ }
+ this.setState({ uploadProgress: percentCompleted });
+ };
+
+ onUploadFinished = () => {
+ this.updateUploadStatus();
+ };
+
+ showProgressBar() {
+ this.setState({ showProgressBar: true });
+ }
+
+ hideProgressBar() {
+ this.setState({ showProgressBar: false });
+ }
+
+ resetUploadProgress(milliseconds) {
+ setTimeout(() => {
+ this.setState({ uploadProgress: 0 });
+ this.hideProgressBar();
+ }, milliseconds);
+ }
+
startUploading(files) {
let {
onUpload,
@@ -244,9 +321,21 @@ class SoftwareProductLandingPageView extends React.Component {
this.refs.fileInput.value = '';
if (validationData) {
- onUploadConfirmation(currentSoftwareProduct.id, formData);
+ onUploadConfirmation(
+ currentSoftwareProduct.id,
+ formData,
+ () => this.onUploadStart(),
+ this.onUploadProgress,
+ this.onUploadFinished
+ );
} else {
- onUpload(currentSoftwareProduct.id, formData);
+ onUpload(
+ currentSoftwareProduct.id,
+ formData,
+ () => this.onUploadStart(),
+ this.onUploadProgress,
+ this.onUploadFinished
+ );
}
}
}
diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/VspUploadStatus.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/VspUploadStatus.js
new file mode 100644
index 0000000000..abb2a98c98
--- /dev/null
+++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/VspUploadStatus.js
@@ -0,0 +1,73 @@
+/*
+ * -
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2022 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 i18n from 'nfvo-utils/i18n/i18n';
+
+export default class VspUploadStatus {
+ static UPLOADING = 'UPLOADING';
+ static VALIDATING = 'VALIDATING';
+ static PROCESSING = 'PROCESSING';
+ static SUCCESS = 'SUCCESS';
+ static ERROR = 'ERROR';
+
+ complete;
+ created;
+ lockId;
+ status;
+ updated;
+ vspId;
+ vspVersionId;
+
+ constructor(vspUploadStatusResponse) {
+ this.status = vspUploadStatusResponse.status;
+ this.complete = vspUploadStatusResponse.complete;
+ this.created = vspUploadStatusResponse.created;
+ this.lockId = vspUploadStatusResponse.lockId;
+ this.updated = vspUploadStatusResponse.updated;
+ this.vspId = vspUploadStatusResponse.vspId;
+ this.vspVersionId = vspUploadStatusResponse.vspVersionId;
+ }
+
+ statusToString() {
+ if (!this.status) {
+ return '';
+ }
+ switch (this.status) {
+ case VspUploadStatus.UPLOADING: {
+ return i18n('upload.status.uploading');
+ }
+ case VspUploadStatus.VALIDATING: {
+ return i18n('upload.status.validating');
+ }
+ case VspUploadStatus.PROCESSING: {
+ return i18n('upload.status.processing');
+ }
+ case VspUploadStatus.SUCCESS: {
+ return i18n('upload.status.success');
+ }
+ case VspUploadStatus.ERROR: {
+ return i18n('upload.status.error');
+ }
+ default:
+ return this.status;
+ }
+ }
+}
diff --git a/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js b/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js
index 2ef1d9fce8..de7db29ad7 100644
--- a/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js
+++ b/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js
@@ -39,6 +39,7 @@ describe('Software Product Landing Page: ', function () {
let currentSoftwareProduct = {}, softwareProductCategories = [], currentScreen = {},
finalizedLicenseModelList, licenseAgreementList, featureGroupsList, qschema, qdata = {};
const dummyFunc = () => {};
+ const fetchUploadStatusMock = () => { return Promise.resolve({ data: {} }) };
beforeAll(function() {
finalizedLicenseModelList = FinalizedLicenseModelFactory.buildList(2);
@@ -96,7 +97,8 @@ describe('Software Product Landing Page: ', function () {
...currentScreen.props,
currentSoftwareProduct,
componentsList: VSPComponentsFactory.buildList(2),
- features: [{name:'EXTERNAL_LICENSE', active: true}]
+ features: [{name:'EXTERNAL_LICENSE', active: true}],
+ fetchUploadStatus: fetchUploadStatusMock
};
const store = storeCreator();
@@ -113,7 +115,8 @@ describe('Software Product Landing Page: ', function () {
...currentScreen.props,
currentSoftwareProduct,
componentsList: VSPComponentsFactory.buildList(2),
- features: [{name:'EXTERNAL_LICENSE', active: true}]
+ features: [{name:'EXTERNAL_LICENSE', active: true}],
+ fetchUploadStatus: fetchUploadStatusMock
};
const e = { target: {
value: 'INTERNAL'
@@ -143,7 +146,8 @@ describe('Software Product Landing Page: ', function () {
currentSoftwareProduct,
...currentScreen.props,
componentsList: VSPComponentsFactory.buildList(2),
- features: [{name:'EXTERNAL_LICENSE', active: true}]
+ features: [{name:'EXTERNAL_LICENSE', active: true}],
+ fetchUploadStatus: fetchUploadStatusMock
};
const store = storeCreator();
@@ -171,7 +175,8 @@ describe('Software Product Landing Page: ', function () {
onUploadConfirmation: dummyFunc,
onUpload: dummyFunc,
onInvalidFileSizeUpload: dummyFunc,
- features: [{name:'EXTERNAL_LICENSE', active: true}]
+ features: [{name:'EXTERNAL_LICENSE', active: true}],
+ fetchUploadStatus: fetchUploadStatusMock
};
const files = [
@@ -215,7 +220,8 @@ describe('Software Product Landing Page: ', function () {
onUploadConfirmation: dummyFunc,
onUpload: dummyFunc,
onInvalidFileSizeUpload: dummyFunc,
- features: [{name:'EXTERNAL_LICENSE', active: true}]
+ features: [{name:'EXTERNAL_LICENSE', active: true}],
+ fetchUploadStatus: fetchUploadStatusMock
};
const store = storeCreator();