diff --git a/locales/en/plugin__odf-console.json b/locales/en/plugin__odf-console.json index 7e492cf5e..7a119742d 100644 --- a/locales/en/plugin__odf-console.json +++ b/locales/en/plugin__odf-console.json @@ -1156,6 +1156,10 @@ "Search a bucket by name": "Search a bucket by name", "Create bucket": "Create bucket", "Browse, upload, and manage objects in buckets.": "Browse, upload, and manage objects in buckets.", + "Could not load information": "Could not load information", + "The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).": "The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).", + "To establish a connection with the endpoint, try the following methods:": "To establish a connection with the endpoint, try the following methods:", + "<0><0>1. Recommended: Replace the internal certificate with one issued by a public or custom Certificate Authority (CA). See the <3>OpenShift documentation for guidance.<6><7>2. Alternative method: Add the internal CA bundle of OpenShift Container Platform to the trust store of your system. This ensures that the browser recognises the internal certificate. <10>(<1>ConfigMap: default-ingress-cert in <3>Namespace: openshift-config-managed).<12><13>3. Temporary (Least recommended): Open the endpoint in a new tab (<15>click here to open the S3 route) and click <17>Continue to site (wording may vary by browser) to bypass the security warning. Then refresh the Data Foundation tab.": "<0><0>1. Recommended: Replace the internal certificate with one issued by a public or custom Certificate Authority (CA). See the <3>OpenShift documentation for guidance.<6><7>2. Alternative method: Add the internal CA bundle of OpenShift Container Platform to the trust store of your system. This ensures that the browser recognises the internal certificate. <10>(<1>ConfigMap: default-ingress-cert in <3>Namespace: openshift-config-managed).<12><13>3. Temporary (Least recommended): Open the endpoint in a new tab (<15>click here to open the S3 route) and click <17>Continue to site (wording may vary by browser) to bypass the security warning. Then refresh the Data Foundation tab.", "Create Bucket": "Create Bucket", "An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.": "An object bucket is a cloud storage container that organizes and manages files (objects), allowing users to store, retrieve and control access to data efficiently.", "Select bucket creation method": "Select bucket creation method", diff --git a/packages/ocs/dashboards/common/details-card/encryption-popover.tsx b/packages/ocs/dashboards/common/details-card/encryption-popover.tsx index 815f89c62..be3a35810 100644 --- a/packages/ocs/dashboards/common/details-card/encryption-popover.tsx +++ b/packages/ocs/dashboards/common/details-card/encryption-popover.tsx @@ -6,7 +6,7 @@ import { ConfigMapKind, ConfigMapModel, GreenCheckCircleIcon, - TimesCircleIcon, + RedTimesIcon, } from '@odf/shared'; import { StorageClusterKind } from '@odf/shared/types'; import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook'; @@ -30,7 +30,7 @@ type EncryptionPopoverProps = { }; const StatusIcon: React.FC<{ enabled: boolean }> = ({ enabled }) => - enabled ? : ; + enabled ? : ; const getKmsTypeDescription = (encryptionKMSType: string, t: TFunction) => { let provider = ''; diff --git a/packages/odf/components/s3-browser/buckets-list-page/bucketsListPage.tsx b/packages/odf/components/s3-browser/buckets-list-page/bucketsListPage.tsx index 8acaaf582..46753b9ea 100644 --- a/packages/odf/components/s3-browser/buckets-list-page/bucketsListPage.tsx +++ b/packages/odf/components/s3-browser/buckets-list-page/bucketsListPage.tsx @@ -13,16 +13,24 @@ import { Button, ButtonVariant, Flex, FlexItem } from '@patternfly/react-core'; import { SyncAltIcon } from '@patternfly/react-icons'; import { BUCKET_CREATE_PAGE_PATH } from '../../../constants'; import { BucketCrFormat } from '../../../types'; +import { isCAError, CAErrorMessage } from '../ca-error/CAErrorMessage'; import { NoobaaS3Provider } from '../noobaa-context'; import { BucketsListTable } from './bucketListTable'; import { BucketPagination } from './bucketPagination'; -const BucketsListPageBody: React.FC = () => { +type BucketInfo = [BucketCrFormat[], boolean, any]; + +type BucketsListPageBodyProps = { + bucketInfo: BucketInfo; + setBucketInfo: React.Dispatch>; +}; + +const BucketsListPageBody: React.FC = ({ + bucketInfo, + setBucketInfo, +}) => { const { t } = useCustomTranslation(); const [fresh, triggerRefresh] = useRefresh(); - const [bucketInfo, setBucketInfo] = React.useState< - [BucketCrFormat[], boolean, any] - >([[], false, undefined]); const [buckets, loaded, loadError] = bucketInfo; const [allBuckets, filteredBuckets, onFilterChange] = useListPageFilter(buckets); @@ -69,11 +77,21 @@ const BucketsListPageBody: React.FC = () => { ); }; -const BucketsListPage: React.FC = () => { +const BucketsListPageContent: React.FC = () => { const { t } = useCustomTranslation(); + const [bucketInfo, setBucketInfo] = React.useState([ + [], + false, + undefined, + ]); + const [_buckets, _loaded, loadError] = bucketInfo; + + if (isCAError(loadError)) { + return ; + } return ( - + <> {t('Create bucket')} @@ -82,7 +100,18 @@ const BucketsListPage: React.FC = () => {
{t('Browse, upload, and manage objects in buckets.')}
- + + + ); +}; + +const BucketsListPage: React.FC = () => { + return ( + + ); }; diff --git a/packages/odf/components/s3-browser/ca-error/CAErrorMessage.tsx b/packages/odf/components/s3-browser/ca-error/CAErrorMessage.tsx new file mode 100644 index 000000000..971ad9f40 --- /dev/null +++ b/packages/odf/components/s3-browser/ca-error/CAErrorMessage.tsx @@ -0,0 +1,91 @@ +import * as React from 'react'; +import { NoobaaS3Context } from '@odf/core/components/s3-browser/noobaa-context'; +import { RedTimesCircleIcon } from '@odf/shared'; +import { DOC_VERSION } from '@odf/shared/hooks'; +import { useCustomTranslation } from '@odf/shared/useCustomTranslationHook'; +import { ExternalLink } from '@odf/shared/utils'; +import { Trans } from 'react-i18next'; +import { + EmptyState, + EmptyStateHeader, + EmptyStateBody, + EmptyStateIcon, + EmptyStateVariant, +} from '@patternfly/react-core'; + +const customCADocLink = (docVersion: string) => + `https://docs.openshift.com/container-platform/${docVersion}/security/certificates/replacing-default-ingress-certificate.html`; + +// In a browser environment, the error objects returned by AWS SDK do not include granular information about TLS or certificate-specific issues. +// Hence relying on error "name" and "message" content. +export const isCAError = (error: Error) => { + const errorMessage = error?.message.toLowerCase(); + const errorType = error?.name; + if ( + ['TypeError', 'NetworkingError', 'NetworkError'].includes(errorType) && + (errorMessage.includes('certificate') || + errorMessage.includes('authority') || + errorMessage.includes('ssl') || + errorMessage.includes('tls') || + errorMessage.includes('self-signed') || + errorMessage.includes('self signed') || + errorMessage.includes('failed to fetch') || + errorMessage.includes('load failed') || + errorMessage.includes('network')) + ) + return true; + return false; +}; + +export const CAErrorMessage: React.FC = () => { + const { t } = useCustomTranslation(); + const { noobaaS3Route } = React.useContext(NoobaaS3Context); + + return ( + <> + + } + headingLevel="h4" + /> + + {t( + 'The browser cannot connect securely to this endpoint because it does not recognize the SSL certificate. This occurs when the certificate of the endpoint is not issued by a trusted Certificate Authority (CA).' + )} +

+ {t( + 'To establish a connection with the endpoint, try the following methods:' + )} +

+
+
+ +
+ 1. Recommended: Replace the internal certificate with one + issued by a public or custom Certificate Authority (CA). See the{' '} + + OpenShift documentation + {' '} + for guidance. +
+ 2. Alternative method: Add the internal CA bundle of OpenShift + Container Platform to the trust store of your system. This ensures + that the browser recognises the internal certificate.{' '} + + (ConfigMap: default-ingress-cert in Namespace:{' '} + openshift-config-managed) + + .
+ 3. Temporary (Least recommended): Open the endpoint in a new + tab ( + + click here to open the S3 route + + ) and click Continue to site (wording may vary by browser) to + bypass the security warning. Then refresh the Data Foundation tab. +
+
+ + ); +}; diff --git a/packages/odf/components/s3-browser/noobaa-context.tsx b/packages/odf/components/s3-browser/noobaa-context.tsx index 0a787ae33..8cbccc9fd 100644 --- a/packages/odf/components/s3-browser/noobaa-context.tsx +++ b/packages/odf/components/s3-browser/noobaa-context.tsx @@ -15,6 +15,7 @@ import { type NoobaaS3ContextType = { noobaaS3: S3Commands; + noobaaS3Route: string; }; type NoobaaS3ProviderType = { @@ -44,16 +45,21 @@ export const NoobaaS3Provider: React.FC = ({ NOOBAA_S3_ROUTE ); + const s3Route = React.useRef(); + const [noobaaS3, noobaaS3Error]: [S3Commands, unknown] = React.useMemo(() => { if (!_.isEmpty(secretData) && !_.isEmpty(routeData)) { try { - const endpoint = `https://${routeData.spec.host}`; + s3Route.current = `https://${routeData.spec.host}`; const accessKeyId = atob(secretData.data?.[NOOBAA_ACCESS_KEY_ID]); const secretAccessKey = atob( secretData.data?.[NOOBAA_SECRET_ACCESS_KEY] ); - return [new S3Commands(endpoint, accessKeyId, secretAccessKey), null]; + return [ + new S3Commands(s3Route.current, accessKeyId, secretAccessKey), + null, + ]; } catch (err) { return [{} as S3Commands, err]; } @@ -71,7 +77,9 @@ export const NoobaaS3Provider: React.FC = ({ odfNsLoadError || secretError || routeError || noobaaS3Error || error; return allLoaded && !anyError ? ( - + {children} ) : ( diff --git a/packages/shared/src/constants/doc.ts b/packages/shared/src/constants/doc.ts index 3167d85e7..4088b19f3 100644 --- a/packages/shared/src/constants/doc.ts +++ b/packages/shared/src/constants/doc.ts @@ -1,5 +1,5 @@ -export const ODF_DEFAULT_DOC_VERSION = '4.16'; -export const ACM_DEFAULT_DOC_VERSION = '2.10'; +export const ODF_DEFAULT_DOC_VERSION = '4.18'; +export const ACM_DEFAULT_DOC_VERSION = '2.12'; export const odfDocHome = (odfDocVersion) => `https://access.redhat.com/documentation/en-us/red_hat_openshift_data_foundation/${odfDocVersion}`; diff --git a/packages/shared/src/status/icons.tsx b/packages/shared/src/status/icons.tsx index 23a7a0670..a273607fa 100644 --- a/packages/shared/src/status/icons.tsx +++ b/packages/shared/src/status/icons.tsx @@ -17,6 +17,7 @@ import { ResourcesAlmostFullIcon, ResourcesFullIcon, TimesIcon, + TimesCircleIcon, } from '@patternfly/react-icons'; export type ColoredIconProps = { @@ -146,9 +147,20 @@ export const BlueArrowCircleUpIcon: React.FC = ({ /> ); -export const TimesCircleIcon: React.FC = ({ +export const RedTimesIcon: React.FC = ({ className, title, }) => ( ); + +export const RedTimesCircleIcon: React.FC = ({ + className, + title, +}) => ( + +);