diff --git a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx index 8b99803ef8..b135d22484 100644 --- a/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx +++ b/portal-ui/src/screens/Console/Buckets/BucketDetails/BrowserHandler.tsx @@ -26,6 +26,7 @@ import { containerForHeader } from "../../Common/FormComponents/common/styleLibr import ListObjects from "../ListBuckets/Objects/ListObjects/ListObjects"; import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions"; import { + errorInConnection, newMessage, resetMessages, setIsOpeningOD, @@ -70,7 +71,8 @@ let wsInFlight: boolean = false; const initWSConnection = ( openCallback?: () => void, - onMessageCallback?: (message: IMessageEvent) => void + onMessageCallback?: (message: IMessageEvent) => void, + connErrorCallback?: (message: string) => void ) => { if (wsInFlight) { return; @@ -104,10 +106,17 @@ const initWSConnection = ( const reconnectFn = () => { if (errorCounter <= 5) { - initWSConnection(() => {}, onMessageCallback); + initWSConnection(() => {}, onMessageCallback, connErrorCallback); errorCounter += 1; } else { - console.error("Websocket not available."); + console.error( + "Websocket not available. Please review that your environment settings are enabled to allow websocket connections and that requests are made from the same origin." + ); + if (connErrorCallback) { + connErrorCallback( + "Couldn't establish WebSocket connection. Please review your configuration and try again." + ); + } } }; @@ -245,6 +254,7 @@ const BrowserHandler = () => { try { const newRequestID = currentRequestID + 1; dispatch(resetMessages()); + dispatch(errorInConnection(false)); const request: WebsocketRequest = { bucket_name: bucketName, @@ -266,7 +276,18 @@ const BrowserHandler = () => { const dupRequest = () => { initWSRequest(path, date); }; - initWSConnection(dupRequest, onMessageCallBack); + + const fatalWSError = (message: string) => { + dispatch( + setErrorSnackMessage({ + errorMessage: message, + detailedError: message, + }) + ); + dispatch(errorInConnection(true)); + }; + + initWSConnection(dupRequest, onMessageCallBack, fatalWSError); } }, [bucketName, rewindEnabled, showDeleted, dispatch, onMessageCallBack] diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjectsTable.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjectsTable.tsx index 61b1ba4065..272700d6ee 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjectsTable.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjectsTable.tsx @@ -117,9 +117,13 @@ const ListObjectsTable = ({ internalPaths }: IListObjectTable) => { const selectedObjects = useSelector( (state: AppState) => state.objectBrowser.selectedObjects ); + const connectionError = useSelector( + (state: AppState) => state.objectBrowser.connectionError + ); const anonymousMode = useSelector( (state: AppState) => state.system.anonymousMode ); + const displayListObjects = hasPermission(bucketName, [ IAM_SCOPES.S3_LIST_BUCKET, IAM_SCOPES.S3_ALL_LIST_BUCKET, @@ -228,6 +232,21 @@ const ListObjectsTable = ({ internalPaths }: IListObjectTable) => { return elements; }; + let errorMessage = + !displayListObjects && !anonymousMode + ? permissionTooltipHelper( + [IAM_SCOPES.S3_LIST_BUCKET, IAM_SCOPES.S3_ALL_LIST_BUCKET], + "view Objects in this bucket" + ) + : `This location is empty${ + !rewindEnabled ? ", please try uploading a new file" : "" + }`; + + if (connectionError) { + errorMessage = + "Objects List unavailable. Please review your WebSockets configuration and try again"; + } + return ( { } ${detailsOpen ? "actionsPanelOpen" : ""}`} selectedItems={selectedObjects} onSelect={!anonymousMode ? selectListObjects : undefined} - customEmptyMessage={ - !displayListObjects && !anonymousMode - ? permissionTooltipHelper( - [IAM_SCOPES.S3_LIST_BUCKET, IAM_SCOPES.S3_ALL_LIST_BUCKET], - "view Objects in this bucket" - ) - : `This location is empty${ - !rewindEnabled ? ", please try uploading a new file" : "" - }` - } + customEmptyMessage={errorMessage} sortConfig={{ currentSort: currentSortField, currentDirection: sortDirection, diff --git a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts index 9851ea82a0..f1a9cceed0 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/objectBrowserSlice.ts @@ -36,6 +36,7 @@ const initialState: ObjectBrowserState = { objectDetailsOpen: false, loadingVersions: true, loadingObjectInfo: true, + connectionError: false, rewind: { ...defaultRewind, }, @@ -365,6 +366,14 @@ export const objectBrowserSlice = createSlice({ setAnonymousAccessOpen: (state, action: PayloadAction) => { state.anonymousAccessOpen = action.payload; }, + errorInConnection: (state, action: PayloadAction) => { + state.connectionError = action.payload; + if (action.payload) { + state.loadingObjects = false; + state.loadingObjectInfo = false; + state.objectDetailsOpen = false; + } + }, }, }); export const { @@ -412,6 +421,7 @@ export const { setSelectedBucket, setLongFileOpen, setAnonymousAccessOpen, + errorInConnection, } = objectBrowserSlice.actions; export default objectBrowserSlice.reducer; diff --git a/portal-ui/src/screens/Console/ObjectBrowser/types.ts b/portal-ui/src/screens/Console/ObjectBrowser/types.ts index 7f11f23f18..2a099b88c3 100644 --- a/portal-ui/src/screens/Console/ObjectBrowser/types.ts +++ b/portal-ui/src/screens/Console/ObjectBrowser/types.ts @@ -96,6 +96,7 @@ export interface ObjectBrowserState { retentionConfig: IRetentionConfig | null; longFileOpen: boolean; anonymousAccessOpen: boolean; + connectionError: boolean; } export interface ObjectManager {