diff --git a/.cursor/rules/translations.mdc b/.cursor/rules/translations.mdc
index 7dd7021dec..dd5e48b3b8 100644
--- a/.cursor/rules/translations.mdc
+++ b/.cursor/rules/translations.mdc
@@ -42,6 +42,7 @@ yarn workspace @openshift-assisted/locales run validate_translation_files
- **`lib/es/`, `lib/fr/`, `lib/ja/`, `lib/ko/`, `lib/zh/`** — Handled by a separate localization
process. **Do not edit** those `translation.json` files.
- **`libs/ui-lib/lib/ocm/**`** — No **`t('ai:…')`**; use plain English strings or text supplied via props.
+- **Bare string literals in `i18nKey` or other translation props** — Always wrap `'ai:…'` strings with `t()` even when assigning to props like `i18nKey`.
## Allowed edits
diff --git a/libs/locales/lib/en/translation.json b/libs/locales/lib/en/translation.json
index 1d7552aecd..20e0178cbc 100644
--- a/libs/locales/lib/en/translation.json
+++ b/libs/locales/lib/en/translation.json
@@ -742,6 +742,7 @@
"ai:Progress": "Progress",
"ai:Provide a comma separated list of valid DNS names or IP addresses.": "Provide a comma separated list of valid DNS names or IP addresses.",
"ai:Provide a valid DNS name or IP Address": "Provide a valid DNS name or IP Address",
+ "ai:Provide a valid HTTP or HTTPS URL.": "Provide a valid HTTP or HTTPS URL.",
"ai:Provide a valid HTTP URL.": "Provide a valid HTTP URL.",
"ai:Provide an SSH key to be able to connect to the hosts for debugging purposes during the discovery process": "Provide an SSH key to be able to connect to the hosts for debugging purposes during the discovery process",
"ai:Provide as many labels as you can to narrow the list to relevant hosts only.": "Provide as many labels as you can to narrow the list to relevant hosts.",
@@ -978,7 +979,7 @@
"ai:Upload a YAML file": "Upload a YAML file",
"ai:Upload a YAML file in NMstate format (not the entire NMstate config CR) that includes your network configuration (static IPs, bonds, etc.).": "Upload a YAML file in NMstate format (not the entire NMstate config CR) that includes your network configuration (static IPs, bonds, etc.).",
"ai:Upload a YAML file with BareMetalHost and Secret resource definitions. Use the provided template as a reference.": "Upload a YAML file with BareMetalHost and Secret resource definitions. Use the provided template as a reference.",
- "ai:URL must start with http (https schemes are not currently supported).": "URL must start with http (https schemes are not currently supported).",
+ "ai:URL must start with http or https.": "URL must start with http or https.",
"ai:URL must start with http.": "URL must start with http.",
"ai:Use a comma to separate each listed domain. Preface a domain with . to include its subdomains. Use * to bypass the proxy for all destinations.": "Use a comma to separate each listed domain. Preface a domain with . to include its subdomains. Use * to bypass the proxy for all destinations.",
"ai:Use advanced networking": "Use advanced networking",
diff --git a/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts b/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts
index cc62cec2b1..2e8f3e1813 100644
--- a/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts
+++ b/libs/ui-lib/lib/cim/components/ClusterDeployment/use-networking-formik.ts
@@ -22,6 +22,7 @@ import {
CLUSTER_DEFAULT_NETWORK_SETTINGS,
clusterNetworksSchema,
serviceNetworksSchema,
+ httpsProxyValidationSchema,
} from '../../../common';
import { ClusterDeploymentNetworkingValues } from './types';
import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
@@ -65,7 +66,7 @@ const getNetworkConfigurationValidationSchema = (
ingressVips: vipArrayValidationSchema(hostSubnets, values, t),
sshPublicKey: sshPublicKeyListValidationSchema(t),
httpProxy: httpProxyValidationSchema({ values, pairValueName: 'httpsProxy', t }),
- httpsProxy: httpProxyValidationSchema({ values, pairValueName: 'httpProxy', t }), // share the schema, httpS is currently not supported
+ httpsProxy: httpsProxyValidationSchema({ values, pairValueName: 'httpProxy', t }),
noProxy: noProxyValidationSchema(t),
}),
);
diff --git a/libs/ui-lib/lib/cim/components/Hypershift/HostedClusterWizard/NetworkStep/NetworkStep.tsx b/libs/ui-lib/lib/cim/components/Hypershift/HostedClusterWizard/NetworkStep/NetworkStep.tsx
index 5e7bf4bb34..a7d5a584a9 100644
--- a/libs/ui-lib/lib/cim/components/Hypershift/HostedClusterWizard/NetworkStep/NetworkStep.tsx
+++ b/libs/ui-lib/lib/cim/components/Hypershift/HostedClusterWizard/NetworkStep/NetworkStep.tsx
@@ -9,6 +9,7 @@ import {
day2ApiVipValidationSchema,
hostPrefixValidationSchema,
httpProxyValidationSchema,
+ httpsProxyValidationSchema,
ipBlockValidationSchema,
noProxyValidationSchema,
sshPublicKeyValidationSchema,
@@ -29,7 +30,7 @@ const getValidationSchema = (t: TFunction) =>
? hostPrefixValidationSchema(values.clusterNetworkCidr, t)
: Yup.number(),
httpProxy: httpProxyValidationSchema({ values, pairValueName: 'httpsProxy', t }),
- httpsProxy: httpProxyValidationSchema({ values, pairValueName: 'httpProxy', t }), // share the schema, httpS is currently not supported
+ httpsProxy: httpsProxyValidationSchema({ values, pairValueName: 'httpProxy', t }), // share the schema, httpS is currently not supported
noProxy: noProxyValidationSchema(t),
nodePortAddress:
values.apiPublishingStrategy === 'NodePort'
diff --git a/libs/ui-lib/lib/cim/components/InfraEnv/InfraEnvFormPage.tsx b/libs/ui-lib/lib/cim/components/InfraEnv/InfraEnvFormPage.tsx
index ae97eb1708..718302df7e 100644
--- a/libs/ui-lib/lib/cim/components/InfraEnv/InfraEnvFormPage.tsx
+++ b/libs/ui-lib/lib/cim/components/InfraEnv/InfraEnvFormPage.tsx
@@ -42,6 +42,7 @@ import {
ntpSourceValidationSchema,
CpuArchitecture,
getOCPStaticIPDocLink,
+ httpsProxyValidationSchema,
} from '../../../common';
import './infra-env.css';
@@ -85,7 +86,7 @@ const validationSchema = (usedNames: string[], t: TFunction) =>
allowEmpty: true,
t,
}),
- httpsProxy: httpProxyValidationSchema({
+ httpsProxy: httpsProxyValidationSchema({
values,
pairValueName: 'httpProxy',
allowEmpty: true,
diff --git a/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx b/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
index 3c2a1c2906..bb79f7b8c0 100644
--- a/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
+++ b/libs/ui-lib/lib/cim/components/modals/AddHostModal.tsx
@@ -9,7 +9,8 @@ import {
ModalVariant,
Spinner,
} from '@patternfly/react-core';
-import { DownloadIso, DiscoveryImageConfigForm, DiscoveryImageFormValues } from '../../../common';
+import { DownloadIso } from '../../../common';
+import { DiscoveryImageConfigForm, DiscoveryImageFormValues } from './DiscoveryImageConfigForm';
import { AddHostModalProps } from './types';
import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
import { EnvironmentErrors } from '../InfraEnv/EnvironmentErrors';
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/DiscoveryImageConfigForm.tsx b/libs/ui-lib/lib/cim/components/modals/DiscoveryImageConfigForm.tsx
similarity index 75%
rename from libs/ui-lib/lib/common/components/clusterConfiguration/DiscoveryImageConfigForm.tsx
rename to libs/ui-lib/lib/cim/components/modals/DiscoveryImageConfigForm.tsx
index 3ff8956af2..014638fa3d 100644
--- a/libs/ui-lib/lib/common/components/clusterConfiguration/DiscoveryImageConfigForm.tsx
+++ b/libs/ui-lib/lib/cim/components/modals/DiscoveryImageConfigForm.tsx
@@ -11,7 +11,6 @@ import {
ModalBody,
ModalFooter,
} from '@patternfly/react-core';
-import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
import { Formik, FormikHelpers } from 'formik';
import {
ImageCreateParams,
@@ -21,40 +20,16 @@ import {
import { AlertFormikError } from '../../../common/components/ui';
import {
httpProxyValidationSchema,
+ httpsProxyValidationSchema,
noProxyValidationSchema,
sshPublicKeyValidationSchema,
-} from '../../validationSchemas';
-import { ProxyFieldsType, StatusErrorType } from '../../types';
-import ProxyFields from './ProxyFields';
-import UploadSSH from './UploadSSH';
-import DiscoveryImageTypeControlGroup from './DiscoveryImageTypeControlGroup';
-import { getOCPStaticIPDocLink } from '../../config/docs_links';
-import { useTranslation } from '../../hooks/use-translation-wrapper';
-
-export const StaticIPInfo = ({ docVersion }: { docVersion?: string }) => {
- const { t } = useTranslation();
- return (
-
- }
- iconPosition="right"
- isInline
- onClick={() =>
- window.open(getOCPStaticIPDocLink(docVersion), '_blank', 'noopener,noreferrer')
- }
- >
- {t('ai:View documentation')}
-
-
- );
-};
+} from '../../../common';
+import { ProxyFieldsType, StatusErrorType } from '../../../common/types';
+import ProxyFields from '../../../common/components/clusterConfiguration/ProxyFields';
+import UploadSSH from '../../../common/components/clusterConfiguration/UploadSSH';
+import DiscoveryImageTypeControlGroup from '../../../common/components/clusterConfiguration/DiscoveryImageTypeControlGroup';
+import { StaticIPInfo } from '../../../common/components/clusterConfiguration/StaticIPInfo';
+import { useTranslation } from '../../../common/hooks/use-translation-wrapper';
export type DiscoveryImageFormValues = ImageCreateParams & ProxyFieldsType;
@@ -63,7 +38,12 @@ const getValidationSchema = (allowEmpty: boolean, t: TFunction) =>
Yup.object().shape({
sshPublicKey: sshPublicKeyValidationSchema(t),
httpProxy: httpProxyValidationSchema({ values, pairValueName: 'httpsProxy', allowEmpty, t }),
- httpsProxy: httpProxyValidationSchema({ values, pairValueName: 'httpProxy', allowEmpty, t }), // share the schema, httpS is currently not supported
+ httpsProxy: httpsProxyValidationSchema({
+ values,
+ pairValueName: 'httpProxy',
+ allowEmpty,
+ t,
+ }),
noProxy: noProxyValidationSchema(t),
}),
);
diff --git a/libs/ui-lib/lib/cim/components/modals/EditProxyModal.tsx b/libs/ui-lib/lib/cim/components/modals/EditProxyModal.tsx
index cb8df33021..b6a51b85bf 100644
--- a/libs/ui-lib/lib/cim/components/modals/EditProxyModal.tsx
+++ b/libs/ui-lib/lib/cim/components/modals/EditProxyModal.tsx
@@ -20,6 +20,7 @@ import { ProxyInputFields } from '../../../common/components/clusterConfiguratio
import { Formik, useFormikContext } from 'formik';
import {
httpProxyValidationSchema,
+ httpsProxyValidationSchema,
noProxyValidationSchema,
ProxyFieldsType,
} from '../../../common';
@@ -35,7 +36,7 @@ const validationSchema = (t: TFunction) =>
allowEmpty: true,
t,
}),
- httpsProxy: httpProxyValidationSchema({
+ httpsProxy: httpsProxyValidationSchema({
values,
pairValueName: 'httpProxy',
allowEmpty: true,
diff --git a/libs/ui-lib/lib/cim/components/modals/types.ts b/libs/ui-lib/lib/cim/components/modals/types.ts
index 8d27c598d2..e259ea4679 100644
--- a/libs/ui-lib/lib/cim/components/modals/types.ts
+++ b/libs/ui-lib/lib/cim/components/modals/types.ts
@@ -1,4 +1,5 @@
-import { DiscoveryImageFormValues, ProxyFieldsType } from '../../../common';
+import { ProxyFieldsType } from '../../../common';
+import { DiscoveryImageFormValues } from './DiscoveryImageConfigForm';
import { BMCFormProps } from '../Agent/types';
import {
BareMetalHostK8sResource,
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx b/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
index 1237acf50f..ceb1758877 100644
--- a/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
+++ b/libs/ui-lib/lib/common/components/clusterConfiguration/DownloadIso.tsx
@@ -12,7 +12,7 @@ import {
} from '@patternfly/react-core';
import { DetailItem, DetailList } from '../ui';
import DiscoveryInstructions from './DiscoveryInstructions';
-import { StaticIPInfo } from './DiscoveryImageConfigForm';
+import { StaticIPInfo } from './StaticIPInfo';
import { useTranslation } from '../../hooks/use-translation-wrapper';
import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
import { getCiscoIntersightLink } from '../../config';
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/ProxyFields.tsx b/libs/ui-lib/lib/common/components/clusterConfiguration/ProxyFields.tsx
index 4edabb08aa..13d0e8afb9 100644
--- a/libs/ui-lib/lib/common/components/clusterConfiguration/ProxyFields.tsx
+++ b/libs/ui-lib/lib/common/components/clusterConfiguration/ProxyFields.tsx
@@ -64,7 +64,7 @@ export const ProxyInputFields = () => {
}}
- i18nKey="ai:URL must start with http (https schemes are not currently supported)."
+ i18nKey={'ai:URL must start with http or https.'}
/>
}
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/StaticIPInfo.tsx b/libs/ui-lib/lib/common/components/clusterConfiguration/StaticIPInfo.tsx
new file mode 100644
index 0000000000..68d26c13c8
--- /dev/null
+++ b/libs/ui-lib/lib/common/components/clusterConfiguration/StaticIPInfo.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { Alert, Button } from '@patternfly/react-core';
+import { ExternalLinkAltIcon } from '@patternfly/react-icons/dist/js/icons/external-link-alt-icon';
+import { getOCPStaticIPDocLink } from '../../config/docs_links';
+import { useTranslation } from '../../hooks/use-translation-wrapper';
+
+export const StaticIPInfo = ({ docVersion }: { docVersion?: string }) => {
+ const { t } = useTranslation();
+ return (
+
+ }
+ iconPosition="right"
+ isInline
+ onClick={() =>
+ window.open(getOCPStaticIPDocLink(docVersion), '_blank', 'noopener,noreferrer')
+ }
+ >
+ {t('ai:View documentation')}
+
+
+ );
+};
diff --git a/libs/ui-lib/lib/common/components/clusterConfiguration/index.ts b/libs/ui-lib/lib/common/components/clusterConfiguration/index.ts
index 91962f2f1e..0b468a048d 100644
--- a/libs/ui-lib/lib/common/components/clusterConfiguration/index.ts
+++ b/libs/ui-lib/lib/common/components/clusterConfiguration/index.ts
@@ -8,5 +8,5 @@ export { default as SecurityFields } from './SecurityFields';
export * from './utils';
export * from './DiscoveryTroubleshootingModal';
-export * from './DiscoveryImageConfigForm';
+export * from './StaticIPInfo';
export * from './ExternalPlatformsDropdown';
diff --git a/libs/ui-lib/lib/common/validationSchemas/proxyValidation.tsx b/libs/ui-lib/lib/common/validationSchemas/proxyValidation.tsx
index 55103ab838..05bd087a48 100644
--- a/libs/ui-lib/lib/common/validationSchemas/proxyValidation.tsx
+++ b/libs/ui-lib/lib/common/validationSchemas/proxyValidation.tsx
@@ -48,6 +48,49 @@ export const httpProxyValidationSchema = ({
);
};
+export const httpsProxyValidationSchema = ({
+ values,
+ pairValueName,
+ allowEmpty,
+ t,
+}: {
+ values: ProxyFieldsType;
+ pairValueName: 'httpProxy' | 'httpsProxy';
+ allowEmpty?: boolean;
+ t: TFunction;
+}) => {
+ const validation = Yup.string().test(
+ 'http-proxy-validation',
+ t('ai:Provide a valid HTTP or HTTPS URL.'),
+ (value?: string) => {
+ if (!value) {
+ return true;
+ }
+
+ if (!['http://', 'https://'].some((protocol) => value.startsWith(protocol))) {
+ return false;
+ }
+
+ try {
+ new URL(value);
+ } catch {
+ return false;
+ }
+ return true;
+ },
+ );
+
+ if (allowEmpty) {
+ return validation;
+ }
+
+ return validation.test(
+ 'http-proxy-no-empty-validation',
+ t('ai:At least one of the HTTP or HTTPS proxy URLs is required.'),
+ (value) => !values.enableProxy || !!value || !!values[pairValueName],
+ );
+};
+
export const noProxyValidationSchema = (t: TFunction) =>
Yup.string().test(
'no-proxy-validation',
diff --git a/libs/ui-lib/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx b/libs/ui-lib/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx
index eef443ada7..00b9789ced 100644
--- a/libs/ui-lib/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx
+++ b/libs/ui-lib/lib/ocm/components/clusterConfiguration/OcmDiscoveryImageConfigForm.tsx
@@ -35,6 +35,7 @@ import DiscoveryImageTypeDropdown, { discoveryImageTypes } from './DiscoveryImag
import CertificateFields from '../../../common/components/clusterConfiguration/CertificateFields';
import {
httpProxyValidationSchema,
+ httpsProxyValidationSchema,
noProxyValidationSchema,
sshPublicKeyValidationSchema,
} from '../../../common';
@@ -60,7 +61,7 @@ const validationSchema = (t: TFunction) =>
Yup.object().shape({
sshPublicKey: sshPublicKeyValidationSchema(t),
httpProxy: httpProxyValidationSchema({ values, pairValueName: 'httpsProxy', t }),
- httpsProxy: httpProxyValidationSchema({ values, pairValueName: 'httpProxy', t }), // share the schema, httpS is currently not supported
+ httpsProxy: httpsProxyValidationSchema({ values, pairValueName: 'httpProxy', t }),
noProxy: noProxyValidationSchema(t),
}),
);