From 1c0632473a60ae89b9b9aa56ca76a70bd5a0f348 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Kuffel?= Date: Wed, 29 Jun 2022 17:26:22 +0200 Subject: [PATCH] Add object-level error message display in Downloads/Uploads panel (#2150) --- .../Objects/ListObjects/ListObjects.tsx | 27 ++++++++-- .../Objects/ListObjects/ObjectDetailPanel.tsx | 5 +- .../ObjectDetails/VersionsNavigator.tsx | 5 +- .../Buckets/ListBuckets/Objects/utils.ts | 51 ++++++++++++------- .../Common/ObjectManager/ObjectHandled.tsx | 13 +++++ .../ObjectBrowser/RenameLongFilename.tsx | 5 +- .../ObjectBrowser/objectBrowserSlice.ts | 7 ++- .../screens/Console/ObjectBrowser/types.ts | 1 + 8 files changed, 82 insertions(+), 32 deletions(-) diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx index 028315e00..f3d285360 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx @@ -783,8 +783,8 @@ const ListObjects = () => { () => { dispatch(completeObject(identityDownload)); }, - () => { - dispatch(failObject(identityDownload)); + (msg: string) => { + dispatch(failObject({ instanceID: identityDownload, msg })); }, () => { dispatch(cancelObjectInList(identityDownload)); @@ -804,6 +804,7 @@ const ListObjects = () => { waitingForFile: true, failed: false, cancelled: false, + errorMessage: "", }) ); @@ -924,14 +925,24 @@ const ListObjects = () => { errorMessage = "something went wrong"; } } - dispatch(failObject(identity)); + dispatch( + failObject({ + instanceID: identity, + msg: errorMessage, + }) + ); reject({ status: xhr.status, message: errorMessage }); } }; xhr.upload.addEventListener("error", (event) => { reject(errorMessage); - dispatch(failObject(identity)); + dispatch( + failObject({ + instanceID: identity, + msg: "A network error occurred.", + }) + ); return; }); @@ -948,7 +959,12 @@ const ListObjects = () => { xhr.onerror = () => { reject(errorMessage); - dispatch(failObject(identity)); + dispatch( + failObject({ + instanceID: identity, + msg: "A network error occurred.", + }) + ); return; }; xhr.onloadend = () => { @@ -977,6 +993,7 @@ const ListObjects = () => { waitingForFile: false, failed: false, cancelled: false, + errorMessage: "", }) ); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx index 9f711d219..a4d085dee 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ObjectDetailPanel.tsx @@ -318,8 +318,8 @@ const ObjectDetailPanel = ({ () => { dispatch(completeObject(identityDownload)); }, - () => { - dispatch(failObject(identityDownload)); + (msg: string) => { + dispatch(failObject({ instanceID: identityDownload, msg })); }, () => { dispatch(cancelObjectInList(identityDownload)); @@ -339,6 +339,7 @@ const ObjectDetailPanel = ({ waitingForFile: true, failed: false, cancelled: false, + errorMessage: "", }) ); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx index d6ef32f91..2582bd596 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/VersionsNavigator.tsx @@ -263,8 +263,8 @@ const VersionsNavigator = ({ () => { dispatch(completeObject(identityDownload)); }, - () => { - dispatch(failObject(identityDownload)); + (msg: string) => { + dispatch(failObject({ instanceID: identityDownload, msg })); }, () => { dispatch(cancelObjectInList(identityDownload)); @@ -284,6 +284,7 @@ const VersionsNavigator = ({ waitingForFile: true, failed: false, cancelled: false, + errorMessage: "", }) ); diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts index 1a6ecc845..01ae2024c 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/utils.ts @@ -26,7 +26,7 @@ export const download = ( overrideFileName: string | null = null, progressCallback: (progress: number) => void, completeCallback: () => void, - errorCallback: () => void, + errorCallback: (msg: string) => void, abortCallback: () => void ) => { const anchor = document.createElement("a"); @@ -56,30 +56,43 @@ export const download = ( req.responseType = "blob"; req.onreadystatechange = () => { - if (req.readyState === 4 && req.status === 200) { - const rspHeader = req.getResponseHeader("Content-Disposition"); + if (req.readyState === 4) { + if (req.status === 200) { + const rspHeader = req.getResponseHeader("Content-Disposition"); - let filename = "download"; - if (rspHeader) { - let rspHeaderDecoded = decodeURIComponent(rspHeader); - filename = rspHeaderDecoded.split('"')[1]; + let filename = "download"; + if (rspHeader) { + let rspHeaderDecoded = decodeURIComponent(rspHeader); + filename = rspHeaderDecoded.split('"')[1]; + } + + if (completeCallback) { + completeCallback(); + } + + var link = document.createElement("a"); + link.href = window.URL.createObjectURL(req.response); + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } else { + if (req.getResponseHeader("Content-Type") === "application/json") { + const rspBody: { detailedMessage?: string } = JSON.parse( + req.response + ); + if (rspBody.detailedMessage) { + errorCallback(rspBody.detailedMessage); + return; + } + } + errorCallback(`Unexpected response status code (${req.status}).`); } - - if (completeCallback) { - completeCallback(); - } - - var link = document.createElement("a"); - link.href = window.URL.createObjectURL(req.response); - link.download = filename; - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); } }; req.onerror = () => { if (errorCallback) { - errorCallback(); + errorCallback("A network error occurred."); } }; req.onabort = () => { diff --git a/portal-ui/src/screens/Console/Common/ObjectManager/ObjectHandled.tsx b/portal-ui/src/screens/Console/Common/ObjectManager/ObjectHandled.tsx index b6221d7aa..be757fc9d 100644 --- a/portal-ui/src/screens/Console/Common/ObjectManager/ObjectHandled.tsx +++ b/portal-ui/src/screens/Console/Common/ObjectManager/ObjectHandled.tsx @@ -144,6 +144,13 @@ const styles = (theme: Theme) => color: "#696969", fontWeight: "normal", }, + errorMessage: { + fontSize: 12, + color: "#C83B51", + fontWeight: "normal", + marginTop: 6, + overflowWrap: "break-word", + }, }); const ObjectHandled = ({ @@ -247,6 +254,12 @@ const ObjectHandled = ({ /> )} + {objectToDisplay.errorMessage !== "" && ( +
+ Error: + {objectToDisplay.errorMessage} +
+ )} ); diff --git a/portal-ui/src/screens/Console/ObjectBrowser/RenameLongFilename.tsx b/portal-ui/src/screens/Console/ObjectBrowser/RenameLongFilename.tsx index c9a5fb265..ba2e0236a 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/RenameLongFilename.tsx +++ b/portal-ui/src/screens/Console/ObjectBrowser/RenameLongFilename.tsx @@ -101,8 +101,8 @@ const RenameLongFileName = ({ () => { dispatch(completeObject(identityDownload)); }, - () => { - dispatch(failObject(identityDownload)); + (msg: string) => { + dispatch(failObject({ instanceID: identityDownload, msg })); }, () => { dispatch(cancelObjectInList(identityDownload)); @@ -122,6 +122,7 @@ const RenameLongFileName = ({ waitingForFile: true, failed: false, cancelled: false, + errorMessage: "", }) ); diff --git a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts index c36588c93..fa1aa29ac 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts @@ -120,12 +120,15 @@ export const objectBrowserSlice = createSlice({ false; state.objectManager.objectsToManage[objectToComplete].done = true; }, - failObject: (state, action: PayloadAction) => { + failObject: (state, action: PayloadAction<{instanceID: string; msg: string}>) => { const objectToFail = state.objectManager.objectsToManage.findIndex( - (item) => item.instanceID === action.payload + (item) => item.instanceID === action.payload.instanceID ); state.objectManager.objectsToManage[objectToFail].failed = true; + state.objectManager.objectsToManage[objectToFail].waitingForFile = false; + state.objectManager.objectsToManage[objectToFail].done = true; + state.objectManager.objectsToManage[objectToFail].errorMessage = action.payload.msg; }, cancelObjectInList: (state, action: PayloadAction) => { const objectToCancel = state.objectManager.objectsToManage.findIndex( diff --git a/portal-ui/src/screens/Console/ObjectBrowser/types.ts b/portal-ui/src/screens/Console/ObjectBrowser/types.ts index d30832306..c829e24ec 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/types.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/types.ts @@ -99,6 +99,7 @@ export interface IFileItem { waitingForFile: boolean; failed: boolean; cancelled: boolean; + errorMessage: string; } interface RewindSetEnabled {