From 59748ca4772264071239d84e85c0f24ef76d7c51 Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Mon, 17 Nov 2025 17:21:03 -0500 Subject: [PATCH 1/6] Build worked and tests are passing --- frontend/package.json | 2 +- .../buildconfig/form-utils/validation.ts | 41 +-- .../utils/deployment-validation-utils.ts | 25 +- .../health-checks-probe-validation-utils.ts | 94 +++---- .../src/components/hpa/validation-utils.ts | 85 +++--- .../components/import/validation-schema.ts | 253 +++++++++--------- .../helmchartrepository-validation-utils.ts | 7 +- .../add/brokers/broker-validation-utils.ts | 11 +- .../add/eventSink-validation-utils.ts | 45 ++-- .../add/eventSource-validation-utils.ts | 210 ++++++++------- .../src/components/sink-source/SinkSource.tsx | 2 +- .../add-baremetal-host/AddBareMetalHost.tsx | 4 +- .../modals/common/validation-utils.ts | 131 ++++----- .../form-switcher-validation.spec.ts | 9 +- .../pipeline-builder/validation-utils.ts | 11 +- .../repository/repository-form-utils.ts | 78 +++--- .../src/components/build-form/validation.ts | 10 +- frontend/packages/vsphere-plugin/package.json | 2 +- .../setup/cloud-shell-setup-utils.ts | 14 +- .../components/configmaps/configmap-utils.ts | 9 +- frontend/yarn.lock | 49 ++-- 21 files changed, 570 insertions(+), 522 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 6cdc07dfed9..2556115231d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -217,7 +217,7 @@ "subscriptions-transport-ws": "^0.9.16", "typesafe-actions": "^4.2.1", "victory": "^37.3.6", - "yup": "^0.27.0" + "yup": "^1.7.1" }, "devDependencies": { "@babel/core": "^7.10.3", diff --git a/frontend/packages/dev-console/src/components/buildconfig/form-utils/validation.ts b/frontend/packages/dev-console/src/components/buildconfig/form-utils/validation.ts index 7c7629382e4..9ce66eea449 100644 --- a/frontend/packages/dev-console/src/components/buildconfig/form-utils/validation.ts +++ b/frontend/packages/dev-console/src/components/buildconfig/form-utils/validation.ts @@ -14,17 +14,18 @@ const sourceSchema = () => .oneOf(['git', 'dockerfile', 'binary']), git: yup.object().when('type', { is: 'git', - then: yup.object({ - git: yup.object({ - url: yup.string().required(i18n.t('devconsole~Required')), - ref: yup.string(), - dir: yup.string(), + then: (schema) => + schema.shape({ + git: yup.object({ + url: yup.string().required(i18n.t('devconsole~Required')), + ref: yup.string(), + dir: yup.string(), + }), }), - }), }), dockerfile: yup.string().when('type', { is: 'dockerfile', - then: yup.string(), + then: (schema) => schema, }), }) .required(i18n.t('devconsole~Required')); @@ -34,21 +35,22 @@ const imageSchema = (allowedTypes: string[]) => type: yup.string().required(i18n.t('devconsole~Required')).oneOf(allowedTypes), imageStreamTag: yup.object().when('type', { is: 'imageStreamTag', - then: yup.object({ - imageStream: yup.object({ - namespace: yup.string().required(i18n.t('devconsole~Required')), - image: yup.string().required(i18n.t('devconsole~Required')), - tag: yup.string().required(i18n.t('devconsole~Required')), + then: (schema) => + schema.shape({ + imageStream: yup.object({ + namespace: yup.string().required(i18n.t('devconsole~Required')), + image: yup.string().required(i18n.t('devconsole~Required')), + tag: yup.string().required(i18n.t('devconsole~Required')), + }), }), - }), }), imageStreamImage: yup.string().when('type', { is: 'imageStreamImage', - then: yup.string().required(i18n.t('devconsole~Required')), + then: (schema) => schema.required(i18n.t('devconsole~Required')), }), dockerImage: yup.string().when('type', { is: 'dockerImage', - then: yup.string().required(i18n.t('devconsole~Required')), + then: (schema) => schema.required(i18n.t('devconsole~Required')), }), }); @@ -82,7 +84,7 @@ const formDataSchema = () => export const validationSchema = () => yup.mixed().test({ - test(values: BuildConfigFormikValues) { + async test(values: BuildConfigFormikValues) { const formYamlDefinition = yup.object({ editorType: yup .string() @@ -90,14 +92,15 @@ export const validationSchema = () => .required(i18n.t('devconsole~Required')), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: formDataSchema(), + then: (schema) => schema.concat(formDataSchema()), }), yamlData: yup.mixed().when('editorType', { is: EditorType.YAML, - then: yup.string().required(i18n.t('devconsole~Required')), + then: (schema) => schema.concat(yup.string().required(i18n.t('devconsole~Required'))), }), }); - return formYamlDefinition.validate(values, { abortEarly: false }); + await formYamlDefinition.validate(values, { abortEarly: false }); + return true; }, }); diff --git a/frontend/packages/dev-console/src/components/deployments/utils/deployment-validation-utils.ts b/frontend/packages/dev-console/src/components/deployments/utils/deployment-validation-utils.ts index 306a6cb54c5..baea745af6f 100644 --- a/frontend/packages/dev-console/src/components/deployments/utils/deployment-validation-utils.ts +++ b/frontend/packages/dev-console/src/components/deployments/utils/deployment-validation-utils.ts @@ -113,32 +113,35 @@ export const editDeploymentFormSchema = (formValues: EditDeploymentFormData) => : {}), imageStream: yup.object().when('fromImageStreamTag', { is: true, - then: yup.object({ - namespace: yup.string().required(i18n.t('devconsole~Required')), - image: yup.string().required(i18n.t('devconsole~Required')), - tag: yup.string().required(i18n.t('devconsole~Required')), - }), + then: (schema) => + schema.shape({ + namespace: yup.string().required(i18n.t('devconsole~Required')), + image: yup.string().required(i18n.t('devconsole~Required')), + tag: yup.string().required(i18n.t('devconsole~Required')), + }), }), isi: yup.object().when('fromImageStreamTag', { is: true, - then: yup.object({ - name: yup.string().required(i18n.t('devconsole~Required')), - }), + then: (schema) => + schema.shape({ + name: yup.string().required(i18n.t('devconsole~Required')), + }), }), }); export const validationSchema = () => yup.mixed().test({ - test(formValues: EditDeploymentData) { + async test(formValues: EditDeploymentData) { const formYamlDefinition = yup.object({ editorType: yup.string().oneOf(Object.values(EditorType)), yamlData: yup.string(), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: editDeploymentFormSchema(formValues.formData), + then: (schema) => schema.concat(editDeploymentFormSchema(formValues.formData)), }), }); - return formYamlDefinition.validate(formValues, { abortEarly: false }); + await formYamlDefinition.validate(formValues, { abortEarly: false }); + return true; }, }); diff --git a/frontend/packages/dev-console/src/components/health-checks/health-checks-probe-validation-utils.ts b/frontend/packages/dev-console/src/components/health-checks/health-checks-probe-validation-utils.ts index 55fb693663b..dcd19a54181 100644 --- a/frontend/packages/dev-console/src/components/health-checks/health-checks-probe-validation-utils.ts +++ b/frontend/packages/dev-console/src/components/health-checks/health-checks-probe-validation-utils.ts @@ -13,55 +13,59 @@ export const healthChecksValidationSchema = (t: TFunction) => modified: yup.boolean(), data: yup.object().when('showForm', { is: true, - then: yup.object().shape({ - periodSeconds: yup - .number() - .integer(t('devconsole~Value must be an integer.')) - .min(1, t('devconsole~Period must be greater than or equal to 1.')) - .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), - initialDelaySeconds: yup - .number() - .integer(t('devconsole~Value must be an integer.')) - .min(0, t('devconsole~Initial delay must be greater than or equal to 0.')) - .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), - failureThreshold: yup - .number() - .integer(t('devconsole~Value must be an integer.')) - .min(1, t('devconsole~Failure threshold must be greater than or equal to 1.')), - timeoutSeconds: yup - .number() - .integer(t('devconsole~Value must be an integer.')) - .min(1, t('devconsole~Timeout must be greater than or equal to 1.')) - .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), - successThreshold: yup - .number() - .integer(t('devconsole~Value must be an integer.')) - .min(1, t('devconsole~Success threshold must be greater than or equal to 1.')) - .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), - requestType: yup.string(), - httpGet: yup.object().when('requestType', { - is: 'httpGet', - then: yup.object({ - path: yup.string().matches(pathRegex, { - message: t('devconsole~Path must start with /.'), - excludeEmptyString: true, - }), - port: yup.number().required(t('devconsole~Required')), + then: (schema) => + schema.shape({ + periodSeconds: yup + .number() + .integer(t('devconsole~Value must be an integer.')) + .min(1, t('devconsole~Period must be greater than or equal to 1.')) + .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), + initialDelaySeconds: yup + .number() + .integer(t('devconsole~Value must be an integer.')) + .min(0, t('devconsole~Initial delay must be greater than or equal to 0.')) + .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), + failureThreshold: yup + .number() + .integer(t('devconsole~Value must be an integer.')) + .min(1, t('devconsole~Failure threshold must be greater than or equal to 1.')), + timeoutSeconds: yup + .number() + .integer(t('devconsole~Value must be an integer.')) + .min(1, t('devconsole~Timeout must be greater than or equal to 1.')) + .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), + successThreshold: yup + .number() + .integer(t('devconsole~Value must be an integer.')) + .min(1, t('devconsole~Success threshold must be greater than or equal to 1.')) + .max(MAX_INT32, t('devconsole~Value is larger than maximum value allowed.')), + requestType: yup.string(), + httpGet: yup.object().when('requestType', { + is: 'httpGet', + then: (httpGetSchema) => + httpGetSchema.shape({ + path: yup.string().matches(pathRegex, { + message: t('devconsole~Path must start with /.'), + excludeEmptyString: true, + }), + port: yup.number().required(t('devconsole~Required')), + }), }), - }), - tcpSocket: yup.object().when('requestType', { - is: 'tcpSocket', - then: yup.object({ - port: yup.number().required(t('devconsole~Required')), + tcpSocket: yup.object().when('requestType', { + is: 'tcpSocket', + then: (tcpSocketSchema) => + tcpSocketSchema.shape({ + port: yup.number().required(t('devconsole~Required')), + }), }), - }), - exec: yup.object().when('requestType', { - is: 'command', - then: yup.object({ - command: yup.array().of(yup.string().required(t('devconsole~Required'))), + exec: yup.object().when('requestType', { + is: 'command', + then: (execSchema) => + execSchema.shape({ + command: yup.array().of(yup.string().required(t('devconsole~Required'))), + }), }), }), - }), }), }); diff --git a/frontend/packages/dev-console/src/components/hpa/validation-utils.ts b/frontend/packages/dev-console/src/components/hpa/validation-utils.ts index ff286966b5e..e23967f95a1 100644 --- a/frontend/packages/dev-console/src/components/hpa/validation-utils.ts +++ b/frontend/packages/dev-console/src/components/hpa/validation-utils.ts @@ -9,49 +9,50 @@ export const hpaValidationSchema = (t: TFunction) => editorType: yup.string(), formData: yup.object().when('editorType', { is: EditorType.Form, - then: yup.object({ - metadata: yup.object({ - name: yup - .string() - .matches(nameRegex, { - message: t( - 'devconsole~Name must consist of lower-case letters, numbers and hyphens. It must start with a letter and end with a letter or number.', + then: (schema) => + schema.shape({ + metadata: yup.object({ + name: yup + .string() + .matches(nameRegex, { + message: t( + 'devconsole~Name must consist of lower-case letters, numbers and hyphens. It must start with a letter and end with a letter or number.', + ), + excludeEmptyString: true, + }) + .max(253, t('devconsole~Cannot be longer than 253 characters.')) + .required(t('devconsole~Required')), + }), + spec: yup.object({ + minReplicas: yup + .number() + .test(isInteger(t('devconsole~Minimum Pods must be an integer.'))) + .min(1, t('devconsole~Minimum Pods must greater than or equal to 1.')) + .test( + 'test-less-than-max', + t('devconsole~Minimum Pods should be less than or equal to Maximum Pods.'), + function (minReplicas) { + const { maxReplicas } = this.parent; + return minReplicas <= maxReplicas; + }, ), - excludeEmptyString: true, - }) - .max(253, t('devconsole~Cannot be longer than 253 characters.')) - .required(t('devconsole~Required')), + maxReplicas: yup + .number() + .test(isInteger(t('devconsole~Maximum Pods must be an integer.'))) + .max( + Number.MAX_SAFE_INTEGER, + t('devconsole~Value is larger than maximum value allowed.'), + ) + .test( + 'test-greater-than-min', + t('devconsole~Maximum Pods should be greater than or equal to Minimum Pods.'), + function (maxReplicas) { + const { minReplicas } = this.parent; + return minReplicas <= maxReplicas; + }, + ) + .required(t('devconsole~Max Pods must be defined.')), + }), }), - spec: yup.object({ - minReplicas: yup - .number() - .test(isInteger(t('devconsole~Minimum Pods must be an integer.'))) - .min(1, t('devconsole~Minimum Pods must greater than or equal to 1.')) - .test( - 'test-less-than-max', - t('devconsole~Minimum Pods should be less than or equal to Maximum Pods.'), - function (minReplicas) { - const { maxReplicas } = this.parent; - return minReplicas <= maxReplicas; - }, - ), - maxReplicas: yup - .number() - .test(isInteger(t('devconsole~Maximum Pods must be an integer.'))) - .max( - Number.MAX_SAFE_INTEGER, - t('devconsole~Value is larger than maximum value allowed.'), - ) - .test( - 'test-greater-than-min', - t('devconsole~Maximum Pods should be greater than or equal to Minimum Pods.'), - function (maxReplicas) { - const { minReplicas } = this.parent; - return minReplicas <= maxReplicas; - }, - ) - .required(t('devconsole~Max Pods must be defined.')), - }), - }), }), }); diff --git a/frontend/packages/dev-console/src/components/import/validation-schema.ts b/frontend/packages/dev-console/src/components/import/validation-schema.ts index 44d86e490c4..d0c1006c3dd 100644 --- a/frontend/packages/dev-console/src/components/import/validation-schema.ts +++ b/frontend/packages/dev-console/src/components/import/validation-schema.ts @@ -45,7 +45,7 @@ export const applicationNameValidationSchema = yup.object().shape({ .max(63, 'Cannot be longer than 63 characters.') .when('selectedKey', { is: CREATE_APPLICATION_KEY, - then: yup.string().required('Required'), + then: (schema) => schema.required('Required'), }), }); @@ -77,100 +77,107 @@ export const resourcesValidationSchema = yup export const serverlessValidationSchema = (t: TFunction) => yup.object().when('resources', { is: Resources.KnativeService, - then: yup.object().shape({ - scaling: yup.object({ - minpods: yup - .number() - .transform((cv) => (_.isNaN(cv) ? undefined : cv)) - .test(isInteger(t('devconsole~Min Pods must be an integer.'))) - .min(0, t('devconsole~Min Pods must be greater than or equal to 0.')) - .max( - Number.MAX_SAFE_INTEGER, - t('devconsole~Min Pods must be lesser than or equal to {{maxSafeInteger}}.', { - maxSafeInteger: Number.MAX_SAFE_INTEGER, - }), - ), - maxpods: yup - .number() - .transform((cv) => (_.isNaN(cv) ? undefined : cv)) - .test(isInteger(t('devconsole~Max Pods must be an integer.'))) - .min(1, t('devconsole~Max Pods must be greater than or equal to 1.')) - .max( - Number.MAX_SAFE_INTEGER, - t('devconsole~Max Pods must be lesser than or equal to {{maxSafeInteger}}.', { - maxSafeInteger: Number.MAX_SAFE_INTEGER, - }), - ) - .test({ - test(limit) { - const { minpods } = this.parent; - return limit ? limit >= minpods : true; - }, - message: t('devconsole~Max Pods must be greater than or equal to Min Pods.'), - }), - concurrencytarget: yup - .number() - .transform((cv) => (_.isNaN(cv) ? undefined : cv)) - .test(isInteger(t('devconsole~Concurrency target must be an integer.'))) - .min(0, t('devconsole~Concurrency target must be greater than or equal to 0.')) - .max( - Number.MAX_SAFE_INTEGER, - t('devconsole~Concurrency target must be lesser than or equal to {{maxSafeInteger}}.', { - maxSafeInteger: Number.MAX_SAFE_INTEGER, - }), - ), - concurrencylimit: yup - .number() - .transform((cv) => (_.isNaN(cv) ? undefined : cv)) - .test(isInteger(t('devconsole~Concurrency limit must be an integer.'))) - .min(0, t('devconsole~Concurrency limit must be greater than or equal to 0.')) - .max( - Number.MAX_SAFE_INTEGER, - t('devconsole~Concurrency limit must be lesser than or equal to {{maxSafeInteger}}.', { - maxSafeInteger: Number.MAX_SAFE_INTEGER, - }), - ), - concurrencyutilization: yup - .number() - .transform((cv) => (_.isNaN(cv) ? undefined : cv)) - .min(0, t('devconsole~Concurrency utilization must be between 0 and 100.')) - .max(100, t('devconsole~Concurrency utilization must be between 0 and 100.')), - autoscale: yup.object().shape({ - autoscalewindow: yup + then: (schema) => + schema.shape({ + scaling: yup.object({ + minpods: yup .number() .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .test(isInteger(t('devconsole~Min Pods must be an integer.'))) + .min(0, t('devconsole~Min Pods must be greater than or equal to 0.')) + .max( + Number.MAX_SAFE_INTEGER, + t('devconsole~Min Pods must be lesser than or equal to {{maxSafeInteger}}.', { + maxSafeInteger: Number.MAX_SAFE_INTEGER, + }), + ), + maxpods: yup + .number() + .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .test(isInteger(t('devconsole~Max Pods must be an integer.'))) + .min(1, t('devconsole~Max Pods must be greater than or equal to 1.')) + .max( + Number.MAX_SAFE_INTEGER, + t('devconsole~Max Pods must be lesser than or equal to {{maxSafeInteger}}.', { + maxSafeInteger: Number.MAX_SAFE_INTEGER, + }), + ) .test({ - test(autoscalewindow) { - if (autoscalewindow) { - const { autoscalewindowUnit } = this.parent; - const value = convertToSec(autoscalewindow, autoscalewindowUnit); - return value >= 6 && value <= 3600; - } - return true; + test(limit) { + const { minpods } = this.parent; + return limit ? limit >= minpods : true; }, - message: t('devconsole~Autoscale window must be between 6s and 1h.'), + message: t('devconsole~Max Pods must be greater than or equal to Min Pods.'), }), + concurrencytarget: yup + .number() + .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .test(isInteger(t('devconsole~Concurrency target must be an integer.'))) + .min(0, t('devconsole~Concurrency target must be greater than or equal to 0.')) + .max( + Number.MAX_SAFE_INTEGER, + t( + 'devconsole~Concurrency target must be lesser than or equal to {{maxSafeInteger}}.', + { + maxSafeInteger: Number.MAX_SAFE_INTEGER, + }, + ), + ), + concurrencylimit: yup + .number() + .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .test(isInteger(t('devconsole~Concurrency limit must be an integer.'))) + .min(0, t('devconsole~Concurrency limit must be greater than or equal to 0.')) + .max( + Number.MAX_SAFE_INTEGER, + t( + 'devconsole~Concurrency limit must be lesser than or equal to {{maxSafeInteger}}.', + { + maxSafeInteger: Number.MAX_SAFE_INTEGER, + }, + ), + ), + concurrencyutilization: yup + .number() + .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .min(0, t('devconsole~Concurrency utilization must be between 0 and 100.')) + .max(100, t('devconsole~Concurrency utilization must be between 0 and 100.')), + autoscale: yup.object().shape({ + autoscalewindow: yup + .number() + .transform((cv) => (_.isNaN(cv) ? undefined : cv)) + .test({ + test(autoscalewindow) { + if (autoscalewindow) { + const { autoscalewindowUnit } = this.parent; + const value = convertToSec(autoscalewindow, autoscalewindowUnit); + return value >= 6 && value <= 3600; + } + return true; + }, + message: t('devconsole~Autoscale window must be between 6s and 1h.'), + }), + }), }), - }), - domainMapping: yup.array().of( - yup - .string() - .transform(removeKsvcInfoFromDomainMapping) - .matches(hostnameRegex, { - message: t( - 'devconsole~Domain name must consist of lower-case letters, numbers, periods, and hyphens. It must start and end with a letter or number.', + domainMapping: yup.array().of( + yup + .string() + .transform(removeKsvcInfoFromDomainMapping) + .matches(hostnameRegex, { + message: t( + 'devconsole~Domain name must consist of lower-case letters, numbers, periods, and hyphens. It must start and end with a letter or number.', + ), + excludeEmptyString: true, + }) + .test( + 'domainname-has-segements', + t('devconsole~Domain name must consist of at least two segments separated by dots.'), + function (domainName: string) { + return domainName.split('.').length >= 2; + }, ), - excludeEmptyString: true, - }) - .test( - 'domainname-has-segements', - t('devconsole~Domain name must consist of at least two segments separated by dots.'), - function (domainName: string) { - return domainName.split('.').length >= 2; - }, - ), - ), - }), + ), + }), }); export const routeValidationSchema = (t: TFunction) => @@ -178,9 +185,10 @@ export const routeValidationSchema = (t: TFunction) => secure: yup.boolean(), tls: yup.object().when('secure', { is: true, - then: yup.object({ - termination: yup.string().required(t('devconsole~Please select a termination type.')), - }), + then: (schema) => + schema.shape({ + termination: yup.string().required(t('devconsole~Please select a termination type.')), + }), }), hostname: yup .string() @@ -223,8 +231,8 @@ export const limitsValidationSchema = (t: TFunction) => }, message: t('devconsole~CPU request must be less than or equal to limit.'), }), - requestUnit: yup.string(t('devconsole~Unit must be millicores or cores.')).ensure(), - limitUnit: yup.string(t('devconsole~Unit must be millicores or cores.')).ensure(), + requestUnit: yup.string().ensure(), + limitUnit: yup.string().ensure(), limit: yup .number() .transform((limit) => (_.isNaN(limit) ? undefined : limit)) @@ -261,7 +269,7 @@ export const limitsValidationSchema = (t: TFunction) => }, message: t('devconsole~Memory request must be less than or equal to limit.'), }), - requestUnit: yup.string(t('devconsole~Unit must be Mi or Gi.')), + requestUnit: yup.string(), limit: yup .number() .transform((limit) => (_.isNaN(limit) ? undefined : limit)) @@ -279,17 +287,18 @@ export const limitsValidationSchema = (t: TFunction) => }, message: t('devconsole~Memory limit must be greater than or equal to request.'), }), - limitUnit: yup.string(t('devconsole~Unit must be Mi or Gi.')), + limitUnit: yup.string(), }), }); export const imageValidationSchema = (t: TFunction) => yup.object().when('build', { is: (build) => build.strategy === 'Source', - then: yup.object().shape({ - selected: yup.string().required(t('devconsole~Required')), - tag: yup.string().required(t('devconsole~Required')), - }), + then: (schema) => + schema.shape({ + selected: yup.string().required(t('devconsole~Required')), + tag: yup.string().required(t('devconsole~Required')), + }), }); export const gitValidationSchema = (t: TFunction) => @@ -301,9 +310,10 @@ export const gitValidationSchema = (t: TFunction) => .required(t('devconsole~Required')), type: yup.string().when('showGitType', { is: true, - then: yup - .string() - .required(t('devconsole~We failed to detect the Git type. Please choose a Git type.')), + then: (schema) => + schema.required( + t('devconsole~We failed to detect the Git type. Please choose a Git type.'), + ), }), showGitType: yup.boolean(), }); @@ -311,26 +321,28 @@ export const gitValidationSchema = (t: TFunction) => export const dockerValidationSchema = (t: TFunction) => yup.object().when('build', { is: (build) => build.strategy === 'Docker', - then: yup.object().shape({ - containerPort: yup - .number() - .test(isInteger(t('devconsole~Container port should be an integer'))), - dockerfilePath: yup.string().required(t('devconsole~Required')), - }), + then: (schema) => + schema.shape({ + containerPort: yup + .number() + .test(isInteger(t('devconsole~Container port should be an integer'))), + dockerfilePath: yup.string().required(t('devconsole~Required')), + }), }); export const devfileValidationSchema = (t: TFunction) => yup.object().when('build', { is: (build) => build.strategy === 'Devfile', - then: yup.object().shape({ - devfilePath: yup.string().required(t('devconsole~Required')), - devfileContent: yup - .string() - .min(1, t('devconsole~Required')) - .required(t('devconsole~Required')), - devfileHasError: yup.boolean().oneOf([false]), - devfileSuggestedResources: yup.object().required(t('devconsole~Required')), - }), + then: (schema) => + schema.shape({ + devfilePath: yup.string().required(t('devconsole~Required')), + devfileContent: yup + .string() + .min(1, t('devconsole~Required')) + .required(t('devconsole~Required')), + devfileHasError: yup.boolean().oneOf([false]), + devfileSuggestedResources: yup.object().required(t('devconsole~Required')), + }), }); export const buildValidationSchema = yup.object().shape({ @@ -354,7 +366,8 @@ export const importFlowPipelineTemplateValidationSchema = yup is: (isPipelineEnabled, buildOption, pipelineType) => (isPipelineEnabled || buildOption === BuildOptions.PIPELINES) && pipelineType !== PipelineType.PAC, - then: yup.object().shape({ - templateSelected: yup.string().required(), - }), + then: (schema) => + schema.shape({ + templateSelected: yup.string().required(), + }), }); diff --git a/frontend/packages/helm-plugin/src/components/forms/HelmChartRepository/helmchartrepository-validation-utils.ts b/frontend/packages/helm-plugin/src/components/forms/HelmChartRepository/helmchartrepository-validation-utils.ts index c86dc982990..8e8e9a83718 100644 --- a/frontend/packages/helm-plugin/src/components/forms/HelmChartRepository/helmchartrepository-validation-utils.ts +++ b/frontend/packages/helm-plugin/src/components/forms/HelmChartRepository/helmchartrepository-validation-utils.ts @@ -32,16 +32,17 @@ export const createHelmChartRepositoryValidationSchema = (t: TFunction) => export const validationSchema = (t: TFunction) => yup.mixed().test({ - test(formValues: HelmChartRepositoryData) { + async test(formValues: HelmChartRepositoryData) { const formYamlDefinition = yup.object({ editorType: yup.string().oneOf(Object.values(EditorType)), yamlData: yup.string(), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: createHelmChartRepositoryValidationSchema(t), + then: (schema) => schema.concat(createHelmChartRepositoryValidationSchema(t)), }), }); - return formYamlDefinition.validate(formValues, { abortEarly: false }); + await formYamlDefinition.validate(formValues, { abortEarly: false }); + return true; }, }); diff --git a/frontend/packages/knative-plugin/src/components/add/brokers/broker-validation-utils.ts b/frontend/packages/knative-plugin/src/components/add/brokers/broker-validation-utils.ts index a9443fc0d30..887e0e45047 100644 --- a/frontend/packages/knative-plugin/src/components/add/brokers/broker-validation-utils.ts +++ b/frontend/packages/knative-plugin/src/components/add/brokers/broker-validation-utils.ts @@ -12,11 +12,12 @@ export const brokerValidationSchema = (t: TFunction) => editorType: yup.string(), formData: yup.object().when('editorType', { is: EditorType.Form, - then: yup.object().shape({ - project: projectNameValidationSchema, - application: applicationNameValidationSchema, - name: nameValidationSchema(t), - }), + then: (schema) => + schema.shape({ + project: projectNameValidationSchema, + application: applicationNameValidationSchema, + name: nameValidationSchema(t), + }), }), yamlData: yup.string(), }); diff --git a/frontend/packages/knative-plugin/src/components/add/eventSink-validation-utils.ts b/frontend/packages/knative-plugin/src/components/add/eventSink-validation-utils.ts index b0e201b11d2..1d3f798b656 100644 --- a/frontend/packages/knative-plugin/src/components/add/eventSink-validation-utils.ts +++ b/frontend/packages/knative-plugin/src/components/add/eventSink-validation-utils.ts @@ -15,13 +15,14 @@ const sourceServiceSchema = (t: TFunction) => .object() .when('sourceType', { is: SinkType.Resource, - then: yup.object().shape({ - name: yup.string().required(t('knative-plugin~Required')), - }), + then: (schema) => + schema.shape({ + name: yup.string().required(t('knative-plugin~Required')), + }), }) .when('sourceType', { is: SinkType.Uri, - then: sinkTypeUriValidation(t), + then: (schema) => schema.concat(sinkTypeUriValidation(t)), }); const sinkDataSpecSchema = (t: TFunction) => @@ -29,23 +30,24 @@ const sinkDataSpecSchema = (t: TFunction) => .object() .when('type', { is: KafkaSinkModel.kind, - then: yup.object().shape({ - [KafkaSinkModel.kind]: yup.object().shape({ - bootstrapServers: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), - topic: yup.string().required(t('knative-plugin~Required')), - auth: yup.object().shape({ - secret: yup.object().shape({ - ref: yup.object().shape({ - name: yup.string(), + then: (schema) => + schema.shape({ + [KafkaSinkModel.kind]: yup.object().shape({ + bootstrapServers: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), + topic: yup.string().required(t('knative-plugin~Required')), + auth: yup.object().shape({ + secret: yup.object().shape({ + ref: yup.object().shape({ + name: yup.string(), + }), }), }), }), }), - }), }) .when('type', { is: CamelKameletBindingModel.kind, - then: yup.object(), + then: (schema) => schema, }); export const eventSinkValidationSchema = (t: TFunction) => @@ -53,13 +55,14 @@ export const eventSinkValidationSchema = (t: TFunction) => editorType: yup.string(), formData: yup.object().when('editorType', { is: EditorType.Form, - then: yup.object().shape({ - project: projectNameValidationSchema, - application: applicationNameValidationSchema, - name: nameValidationSchema(t), - source: sourceServiceSchema(t), - data: sinkDataSpecSchema(t), - }), + then: (schema) => + schema.shape({ + project: projectNameValidationSchema, + application: applicationNameValidationSchema, + name: nameValidationSchema(t), + source: sourceServiceSchema(t), + data: sinkDataSpecSchema(t), + }), }), yamlData: yup.string(), }); diff --git a/frontend/packages/knative-plugin/src/components/add/eventSource-validation-utils.ts b/frontend/packages/knative-plugin/src/components/add/eventSource-validation-utils.ts index 3ccdd3e7aa8..575dba901bf 100644 --- a/frontend/packages/knative-plugin/src/components/add/eventSource-validation-utils.ts +++ b/frontend/packages/knative-plugin/src/components/add/eventSource-validation-utils.ts @@ -24,13 +24,14 @@ const sinkServiceSchema = (t: TFunction) => .object() .when('sinkType', { is: SinkType.Resource, - then: yup.object().shape({ - name: yup.string().required(t('knative-plugin~Required')), - }), + then: (schema) => + schema.shape({ + name: yup.string().required(t('knative-plugin~Required')), + }), }) .when('sinkType', { is: SinkType.Uri, - then: sinkTypeUriValidation(t), + then: (schema) => schema.concat(sinkTypeUriValidation(t)), }); export const sourceDataSpecSchema = (t: TFunction) => @@ -38,119 +39,124 @@ export const sourceDataSpecSchema = (t: TFunction) => .object() .when('type', { is: EventSources.PingSource, - then: yup.object().shape({ - [EventSources.PingSource]: yup.object().shape({ - data: yup.string().max(253, t('knative-plugin~Cannot be longer than 253 characters.')), - schedule: yup - .string() - .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) - .required(t('knative-plugin~Required')), + then: (schema) => + schema.shape({ + [EventSources.PingSource]: yup.object().shape({ + data: yup.string().max(253, t('knative-plugin~Cannot be longer than 253 characters.')), + schedule: yup + .string() + .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) + .required(t('knative-plugin~Required')), + }), }), - }), }) .when('type', { is: EventSources.SinkBinding, - then: yup.object().shape({ - [EventSources.SinkBinding]: yup.object().shape({ - subject: yup.object().shape({ - selector: yup.object().shape({ - matchLabels: yup.object(), - }), - name: yup.string().when('selector.matchLabels', { - is: (obj: object) => !obj, - then: yup.string().required(t('knative-plugin~Required')), + then: (schema) => + schema.shape({ + [EventSources.SinkBinding]: yup.object().shape({ + subject: yup.object().shape({ + selector: yup.object().shape({ + matchLabels: yup.object(), + }), + name: yup.string().when('selector.matchLabels', { + is: (obj: object) => !obj, + then: (nameSchema) => nameSchema.required(t('knative-plugin~Required')), + }), + apiVersion: yup + .string() + .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) + .required(t('knative-plugin~Required')), + kind: yup + .string() + .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) + .required(t('knative-plugin~Required')), }), - apiVersion: yup - .string() - .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) - .required(t('knative-plugin~Required')), - kind: yup - .string() - .max(253, t('knative-plugin~Cannot be longer than 253 characters.')) - .required(t('knative-plugin~Required')), }), }), - }), }) .when('type', { is: EventSources.ApiServerSource, - then: yup.object().shape({ - [EventSources.ApiServerSource]: yup.object().shape({ - resources: yup - .array() - .of( - yup.object({ - apiVersion: yup.string().required(t('knative-plugin~Required')), - kind: yup.string().required(t('knative-plugin~Required')), - }), - ) - .required(t('knative-plugin~Required')), + then: (schema) => + schema.shape({ + [EventSources.ApiServerSource]: yup.object().shape({ + resources: yup + .array() + .of( + yup.object({ + apiVersion: yup.string().required(t('knative-plugin~Required')), + kind: yup.string().required(t('knative-plugin~Required')), + }), + ) + .required(t('knative-plugin~Required')), + }), }), - }), }) .when('type', { is: EventSources.KafkaSource, - then: yup.object().shape({ - [EventSources.KafkaSource]: yup.object().shape({ - bootstrapServers: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), - consumerGroup: yup.string().required(t('knative-plugin~Required')), - topics: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), - net: yup.object().shape({ - sasl: yup.object().shape({ - enable: yup.boolean(), - user: yup.object().shape({ - secretKeyRef: yup.object().shape({ - name: yup.string(), - key: yup.string(), + then: (schema) => + schema.shape({ + [EventSources.KafkaSource]: yup.object().shape({ + bootstrapServers: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), + consumerGroup: yup.string().required(t('knative-plugin~Required')), + topics: yup.array().of(yup.string()).min(1, t('knative-plugin~Required')), + net: yup.object().shape({ + sasl: yup.object().shape({ + enable: yup.boolean(), + user: yup.object().shape({ + secretKeyRef: yup.object().shape({ + name: yup.string(), + key: yup.string(), + }), }), - }), - password: yup.object().shape({ - secretKeyRef: yup.object().shape({ - name: yup.string(), - key: yup.string(), + password: yup.object().shape({ + secretKeyRef: yup.object().shape({ + name: yup.string(), + key: yup.string(), + }), }), }), - }), - tls: yup.object().shape({ - enable: yup.boolean(), - caCert: yup.object().shape({ - secretKeyRef: yup.object().shape({ - name: yup.string(), - key: yup.string(), + tls: yup.object().shape({ + enable: yup.boolean(), + caCert: yup.object().shape({ + secretKeyRef: yup.object().shape({ + name: yup.string(), + key: yup.string(), + }), }), - }), - cert: yup.object().shape({ - secretKeyRef: yup.object().shape({ - name: yup.string(), - key: yup.string(), + cert: yup.object().shape({ + secretKeyRef: yup.object().shape({ + name: yup.string(), + key: yup.string(), + }), }), - }), - key: yup.object().shape({ - secretKeyRef: yup.object().shape({ - name: yup.string(), - key: yup.string(), + key: yup.object().shape({ + secretKeyRef: yup.object().shape({ + name: yup.string(), + key: yup.string(), + }), }), }), }), }), }), - }), }) .when('type', { is: EventSources.ContainerSource, - then: yup.object().shape({ - [EventSources.ContainerSource]: yup.object().shape({ - template: yup.object({ - spec: yup.object({ - containers: yup.array().of( - yup.object({ - image: yup.string().required(t('knative-plugin~Required')), - }), - ), + then: (schema) => + schema.shape({ + [EventSources.ContainerSource]: yup.object().shape({ + template: yup.object({ + spec: yup.object({ + containers: yup.array().of( + yup.object({ + image: yup.string().required(t('knative-plugin~Required')), + }), + ), + }), }), }), }), - }), }); export const eventSourceValidationSchema = (t: TFunction) => @@ -158,13 +164,14 @@ export const eventSourceValidationSchema = (t: TFunction) => editorType: yup.string(), formData: yup.object().when('editorType', { is: EditorType.Form, - then: yup.object().shape({ - project: projectNameValidationSchema, - application: applicationNameValidationSchema, - name: nameValidationSchema(t), - sink: sinkServiceSchema(t), - data: sourceDataSpecSchema(t), - }), + then: (schema) => + schema.shape({ + project: projectNameValidationSchema, + application: applicationNameValidationSchema, + name: nameValidationSchema(t), + sink: sinkServiceSchema(t), + data: sourceDataSpecSchema(t), + }), }), yamlData: yup.string(), }); @@ -174,13 +181,14 @@ export const addChannelValidationSchema = (t: TFunction) => editorType: yup.string(), formData: yup.object().when('editorType', { is: EditorType.Form, - then: yup.object().shape({ - project: projectNameValidationSchema, - application: applicationNameValidationSchema, - name: nameValidationSchema(t), - data: yup.object(), - type: yup.string(), - }), + then: (schema) => + schema.shape({ + project: projectNameValidationSchema, + application: applicationNameValidationSchema, + name: nameValidationSchema(t), + data: yup.object(), + type: yup.string(), + }), }), yamlData: yup.string(), }); diff --git a/frontend/packages/knative-plugin/src/components/sink-source/SinkSource.tsx b/frontend/packages/knative-plugin/src/components/sink-source/SinkSource.tsx index 0643601022d..f2442ba1b63 100644 --- a/frontend/packages/knative-plugin/src/components/sink-source/SinkSource.tsx +++ b/frontend/packages/knative-plugin/src/components/sink-source/SinkSource.tsx @@ -79,7 +79,7 @@ const SinkSource: React.FC = ({ source, cancel, close }) => { formData: yup.object().shape({ sink: yup.object().when('sinkType', { is: SinkType.Uri, - then: sinkTypeUriValidation(t), + then: (schema) => schema.concat(sinkTypeUriValidation(t)), }), }), }) diff --git a/frontend/packages/metal3-plugin/src/components/baremetal-hosts/add-baremetal-host/AddBareMetalHost.tsx b/frontend/packages/metal3-plugin/src/components/baremetal-hosts/add-baremetal-host/AddBareMetalHost.tsx index ca22c28ecd9..5fc7a2d341a 100644 --- a/frontend/packages/metal3-plugin/src/components/baremetal-hosts/add-baremetal-host/AddBareMetalHost.tsx +++ b/frontend/packages/metal3-plugin/src/components/baremetal-hosts/add-baremetal-host/AddBareMetalHost.tsx @@ -132,11 +132,11 @@ const AddBareMetalHost: React.FC = ({ const addHostValidationSchema = Yup.lazy(({ enablePowerManagement }) => Yup.object().shape({ - name: Yup.mixed() + name: Yup.string() .test( 'unique-name', t('metal3-plugin~Name "${value}" is already taken.'), // eslint-disable-line no-template-curly-in-string - (value) => !hostNames.includes(value), + (value: string) => !hostNames.includes(value), ) .concat(nameValidationSchema(t)), BMCAddress: enablePowerManagement diff --git a/frontend/packages/pipelines-plugin/src/components/pipelines/modals/common/validation-utils.ts b/frontend/packages/pipelines-plugin/src/components/pipelines/modals/common/validation-utils.ts index 72dfe43ab5c..dc1c8b6ebbc 100644 --- a/frontend/packages/pipelines-plugin/src/components/pipelines/modals/common/validation-utils.ts +++ b/frontend/packages/pipelines-plugin/src/components/pipelines/modals/common/validation-utils.ts @@ -11,41 +11,46 @@ export const validateResourceType = () => .object() .when('type', { is: PipelineResourceType.git, - then: yup.object({ - url: yup.string().required(i18next.t('pipelines-plugin~Required')), - revision: yup.string(), - }), + then: (schema) => + schema.shape({ + url: yup.string().required(i18next.t('pipelines-plugin~Required')), + revision: yup.string(), + }), }) .when('type', { is: PipelineResourceType.image, - then: yup.object({ - url: yup.string().required(i18next.t('pipelines-plugin~Required')), - }), + then: (schema) => + schema.shape({ + url: yup.string().required(i18next.t('pipelines-plugin~Required')), + }), }) .when('type', { is: PipelineResourceType.storage, - then: yup.object({ - type: yup.string().required(i18next.t('pipelines-plugin~Required')), - location: yup.string().required(i18next.t('pipelines-plugin~Required')), - dir: yup.string(), - }), + then: (schema) => + schema.shape({ + type: yup.string().required(i18next.t('pipelines-plugin~Required')), + location: yup.string().required(i18next.t('pipelines-plugin~Required')), + dir: yup.string(), + }), }) .when('type', { is: PipelineResourceType.cluster, - then: yup.object({ - name: yup.string().required(i18next.t('pipelines-plugin~Required')), - url: yup.string().required(i18next.t('pipelines-plugin~Required')), - username: yup.string().required(i18next.t('pipelines-plugin~Required')), - password: yup.string(), - insecure: yup.string(), - }), + then: (schema) => + schema.shape({ + name: yup.string().required(i18next.t('pipelines-plugin~Required')), + url: yup.string().required(i18next.t('pipelines-plugin~Required')), + username: yup.string().required(i18next.t('pipelines-plugin~Required')), + password: yup.string(), + insecure: yup.string(), + }), }), secrets: yup.object().when('type', { is: PipelineResourceType.cluster, - then: yup.object({ - cadata: yup.string().required(i18next.t('pipelines-plugin~Required')), - token: yup.string(), - }), + then: (schema) => + schema.shape({ + cadata: yup.string().required(i18next.t('pipelines-plugin~Required')), + token: yup.string(), + }), }), }); @@ -56,7 +61,7 @@ export const formResources = () => selection: yup.string().required(i18next.t('pipelines-plugin~Required')), data: yup.object().when('selection', { is: CREATE_PIPELINE_RESOURCE, - then: validateResourceType(), + then: (schema) => schema.concat(validateResourceType()), }), }), ); @@ -66,58 +71,62 @@ const volumeTypeSchema = () => .object() .when('type', { is: (type) => VolumeTypes[type] === VolumeTypes.Secret, - then: yup.object().shape({ - secret: yup.object().shape({ - secretName: yup.string().required(i18next.t('pipelines-plugin~Required')), - items: yup.array().of( - yup.object().shape({ - key: yup.string().required(i18next.t('pipelines-plugin~Required')), - path: yup.string().required(i18next.t('pipelines-plugin~Required')), - }), - ), + then: (schema) => + schema.shape({ + secret: yup.object().shape({ + secretName: yup.string().required(i18next.t('pipelines-plugin~Required')), + items: yup.array().of( + yup.object().shape({ + key: yup.string().required(i18next.t('pipelines-plugin~Required')), + path: yup.string().required(i18next.t('pipelines-plugin~Required')), + }), + ), + }), }), - }), }) .when('type', { is: (type) => VolumeTypes[type] === VolumeTypes.ConfigMap, - then: yup.object().shape({ - configMap: yup.object().shape({ - name: yup.string().required(i18next.t('pipelines-plugin~Required')), - items: yup.array().of( - yup.object().shape({ - key: yup.string().required(i18next.t('pipelines-plugin~Required')), - path: yup.string().required(i18next.t('pipelines-plugin~Required')), - }), - ), + then: (schema) => + schema.shape({ + configMap: yup.object().shape({ + name: yup.string().required(i18next.t('pipelines-plugin~Required')), + items: yup.array().of( + yup.object().shape({ + key: yup.string().required(i18next.t('pipelines-plugin~Required')), + path: yup.string().required(i18next.t('pipelines-plugin~Required')), + }), + ), + }), }), - }), }) .when('type', { is: (type) => VolumeTypes[type] === VolumeTypes.PVC, - then: yup.object().shape({ - persistentVolumeClaim: yup.object().shape({ - claimName: yup.string().required(i18next.t('pipelines-plugin~Required')), + then: (schema) => + schema.shape({ + persistentVolumeClaim: yup.object().shape({ + claimName: yup.string().required(i18next.t('pipelines-plugin~Required')), + }), }), - }), }) .when('type', { is: (type) => VolumeTypes[type] === VolumeTypes.VolumeClaimTemplate, - then: yup.object().shape({ - volumeClaimTemplate: yup.object().shape({ - spec: yup.object().shape({ - accessModes: yup - .array() - .of(yup.string().required(i18next.t('pipelines-plugin~Required'))), - resources: yup.object().shape({ - requests: yup - .object() - .shape({ storage: yup.string().required(i18next.t('pipelines-plugin~Required')) }), + then: (schema) => + schema.shape({ + volumeClaimTemplate: yup.object().shape({ + spec: yup.object().shape({ + accessModes: yup + .array() + .of(yup.string().required(i18next.t('pipelines-plugin~Required'))), + resources: yup.object().shape({ + requests: yup.object().shape({ + storage: yup.string().required(i18next.t('pipelines-plugin~Required')), + }), + }), + storageClassName: yup.string().required(i18next.t('pipelines-plugin~Required')), + volumeMode: yup.string().required(i18next.t('pipelines-plugin~Required')), }), - storageClassName: yup.string().required(i18next.t('pipelines-plugin~Required')), - volumeMode: yup.string().required(i18next.t('pipelines-plugin~Required')), }), }), - }), }); const commonPipelineSchema = () => diff --git a/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/__tests__/form-switcher-validation.spec.ts b/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/__tests__/form-switcher-validation.spec.ts index ec6ad98e281..32f63d2afeb 100644 --- a/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/__tests__/form-switcher-validation.spec.ts +++ b/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/__tests__/form-switcher-validation.spec.ts @@ -1,4 +1,5 @@ import * as _ from 'lodash'; +import { ValidationError } from 'yup'; import { initialPipelineFormData } from '../const'; import { getFormData, @@ -103,7 +104,7 @@ describe('getValidatedFormAndYaml', () => { const invalidYaml = updateYAML('spec.tasks', [ { notName: 'test', taskRef: { name: 'external-task' } }, ]); - const error = { inner: [{ path: 'spec.tasks[0].name' }] }; + const error = { inner: [{ path: 'spec.tasks[0].name' }] } as ValidationError; const finalFormData = getFormData(formDataBasicPassState, updateYAML('spec.tasks', [])); const [sanitizedFormData] = await getValidatedFormAndYaml( formDataBasicPassState, @@ -119,7 +120,7 @@ describe('getValidatedFormAndYaml', () => { { name: 'task2', taskRef: { name: 'external-task2' }, runAfter: ['task2'] }, ]; const invalidYaml = updateYAML('spec.tasks', tasks); - const error = { inner: [{ path: 'spec.tasks[1].runAfter[0]' }] }; + const error = { inner: [{ path: 'spec.tasks[1].runAfter[0]' }] } as ValidationError; const finalFormData = getFormData(formDataBasicPassState, updateYAML('spec.tasks', tasks)); const [sanitizedFormData] = await getValidatedFormAndYaml( formDataBasicPassState, @@ -137,7 +138,7 @@ describe('handleSanitizeToFormError', () => { { name: 'task2', taskRef: { name: 'external-task2' }, runAfter: ['task2'] }, ]; const invalidYaml = updateYAML('spec.tasks', tasks); - const error = { inner: [{ path: 'spec.tasks[1].runAfter[0]' }] }; + const error = { inner: [{ path: 'spec.tasks[1].runAfter[0]' }] } as ValidationError; const finalFormData = getFormData(formDataBasicPassState, updateYAML('spec.tasks', tasks)); const sanitizedFormData = await handleSanitizeToFormError( formDataBasicPassState, @@ -160,7 +161,7 @@ describe('handleSanitizeToFormError', () => { ]; const invalidYaml = updateYAML('spec.tasks', tasks); - const error = { inner: [{ path: 'spec.tasks[1].name' }] }; + const error = { inner: [{ path: 'spec.tasks[1].name' }] } as ValidationError; const finalFormData = getFormData( formDataBasicPassState, updateYAML('spec.tasks', sanitizedTasks), diff --git a/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/validation-utils.ts b/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/validation-utils.ts index 5a686132d98..41740b09858 100644 --- a/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/validation-utils.ts +++ b/frontend/packages/pipelines-plugin/src/components/pipelines/pipeline-builder/validation-utils.ts @@ -279,7 +279,7 @@ const resourceDefinition = (formValues: PipelineBuilderFormYamlValues, taskType: resourceValue?: string, ) { const resource = findResource(formValues, this.path, this.parent.name, taskType); - return !resource || resource.optional || resourceValue; + return !resource || resource.optional || !!resourceValue; }) .test( 'is-resource-link-broken', @@ -391,7 +391,7 @@ const taskValidation = (formValues: PipelineBuilderFormYamlValues, taskType: Tas workspaceValue?: string, ) { const workspace = findWorkspace(formValues, this.path, this.parent.name); - return !workspace || workspace.optional || workspaceValue; + return !workspace || workspace.optional || !!workspaceValue; }) .test( 'are-workspaces-available', @@ -476,16 +476,17 @@ const pipelineBuilderFormSchema = (formValues: PipelineBuilderFormYamlValues) => export const validationSchema = () => yup.mixed().test({ - test(formValues: PipelineBuilderFormYamlValues) { + async test(formValues: PipelineBuilderFormYamlValues) { const formYamlDefinition = yup.object({ editorType: yup.string().oneOf(Object.values(EditorType)), yamlData: yup.string(), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: pipelineBuilderFormSchema(formValues), + then: (schema) => schema.concat(pipelineBuilderFormSchema(formValues)), }), }); - return formYamlDefinition.validate(formValues, { abortEarly: false }); + await formYamlDefinition.validate(formValues, { abortEarly: false }); + return true; }, }); diff --git a/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts b/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts index 41638293840..ab1c66ba3c5 100644 --- a/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts +++ b/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts @@ -45,29 +45,31 @@ export const repositoryValidationSchema = (t: TFunction) => .object() .when('gitProvider', { is: GitProvider.BITBUCKET, - then: yup.object().shape({ - user: yup - .string() - .matches(bitBucketUserNameRegex, { - message: t( - 'pipelines-plugin~Name must consist of lower-case letters, numbers, underscores and hyphens. It must start with a letter and end with a letter or number.', - ), - excludeEmptyString: true, - }) - .required(t('pipelines-plugin~Required')), - }), + then: (schema) => + schema.shape({ + user: yup + .string() + .matches(bitBucketUserNameRegex, { + message: t( + 'pipelines-plugin~Name must consist of lower-case letters, numbers, underscores and hyphens. It must start with a letter and end with a letter or number.', + ), + excludeEmptyString: true, + }) + .required(t('pipelines-plugin~Required')), + }), }) .when(['method', 'gitProvider', 'gitUrl'], { is: (method, gitProvider, gitUrl) => gitUrl && !(gitProvider === GitProvider.GITHUB && method === GitProvider.GITHUB), - then: yup.object().shape({ - token: yup.string().test('oneOfRequired', 'Required', function () { - return this.parent.token || this.parent.secretRef; - }), - secretRef: yup.string().test('oneOfRequired', 'Required', function () { - return this.parent.token || this.parent.secretRef; + then: (schema) => + schema.shape({ + token: yup.string().test('oneOfRequired', 'Required', function () { + return this.parent.token || this.parent.secretRef; + }), + secretRef: yup.string().test('oneOfRequired', 'Required', function () { + return this.parent.token || this.parent.secretRef; + }), }), - }), }), }); @@ -77,31 +79,33 @@ export const pipelinesAccessTokenValidationSchema = (t: TFunction) => .object() .when('gitProvider', { is: GitProvider.BITBUCKET, - then: yup.object().shape({ - user: yup - .string() - .matches(nameRegex, { - message: t( - 'pipelines-plugin~Name must consist of lower-case letters, numbers and hyphens. It must start with a letter and end with a letter or number.', - ), - excludeEmptyString: true, - }) - .required(t('pipelines-plugin~Required')), - }), + then: (schema) => + schema.shape({ + user: yup + .string() + .matches(nameRegex, { + message: t( + 'pipelines-plugin~Name must consist of lower-case letters, numbers and hyphens. It must start with a letter and end with a letter or number.', + ), + excludeEmptyString: true, + }) + .required(t('pipelines-plugin~Required')), + }), }) .when(['method', 'gitProvider', 'gitUrl'], { is: (method, gitProvider, gitUrl) => gitUrl && gitProvider && !(gitProvider === GitProvider.GITHUB && method === GitProvider.GITHUB), - then: yup.object().shape({ - token: yup.string().test('oneOfRequired', 'Required', function () { - return this.parent.token || this.parent.secretRef; - }), - secretRef: yup.string().test('oneOfRequired', 'Required', function () { - return this.parent.token || this.parent.secretRef; + then: (schema) => + schema.shape({ + token: yup.string().test('oneOfRequired', 'Required', function () { + return this.parent.token || this.parent.secretRef; + }), + secretRef: yup.string().test('oneOfRequired', 'Required', function () { + return this.parent.token || this.parent.secretRef; + }), }), - }), }), }); @@ -109,7 +113,7 @@ export const importFlowRepositoryValidationSchema = (t: TFunction) => { return yup.object().shape({ repository: yup.object().when(['pipelineType', 'pipelineEnabled'], { is: (pipelineType, pipelineEnabled) => pipelineType === PipelineType.PAC && pipelineEnabled, - then: pipelinesAccessTokenValidationSchema(t), + then: (schema) => schema.concat(pipelinesAccessTokenValidationSchema(t)), }), }); }; diff --git a/frontend/packages/shipwright-plugin/src/components/build-form/validation.ts b/frontend/packages/shipwright-plugin/src/components/build-form/validation.ts index 5dc94115c3c..f0c61c00795 100644 --- a/frontend/packages/shipwright-plugin/src/components/build-form/validation.ts +++ b/frontend/packages/shipwright-plugin/src/components/build-form/validation.ts @@ -43,7 +43,7 @@ export const formDataSchema = () => export const validationSchema = () => yup.mixed().test({ - test(values: BuildFormikValues) { + async test(values: BuildFormikValues) { const formYamlDefinition = yup.object({ editorType: yup .string() @@ -51,14 +51,16 @@ export const validationSchema = () => .required(i18n.t('shipwright-plugin~Required')), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: formDataSchema(), + then: (schema) => schema.concat(formDataSchema()), }), yamlData: yup.mixed().when('editorType', { is: EditorType.YAML, - then: yup.string().required(i18n.t('shipwright-plugin~Required')), + then: (schema) => + schema.concat(yup.string().required(i18n.t('shipwright-plugin~Required'))), }), }); - return formYamlDefinition.validate(values, { abortEarly: false }); + await formYamlDefinition.validate(values, { abortEarly: false }); + return true; }, }); diff --git a/frontend/packages/vsphere-plugin/package.json b/frontend/packages/vsphere-plugin/package.json index e96c79d5012..f496982bac8 100644 --- a/frontend/packages/vsphere-plugin/package.json +++ b/frontend/packages/vsphere-plugin/package.json @@ -9,7 +9,7 @@ "dependencies": { "@console/dynamic-plugin-sdk": "0.0.0-fixed", "formik": "^2.4.5", - "yup": "^0.27.0" + "yup": "^1.7.1" }, "consolePlugin": { "entry": "src/plugin.ts", diff --git a/frontend/packages/webterminal-plugin/src/components/cloud-shell/setup/cloud-shell-setup-utils.ts b/frontend/packages/webterminal-plugin/src/components/cloud-shell/setup/cloud-shell-setup-utils.ts index 0f92373f6b5..e297250a75b 100644 --- a/frontend/packages/webterminal-plugin/src/components/cloud-shell/setup/cloud-shell-setup-utils.ts +++ b/frontend/packages/webterminal-plugin/src/components/cloud-shell/setup/cloud-shell-setup-utils.ts @@ -20,13 +20,13 @@ const projectNameRegex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/; export const newNamespaceValidationSchema = yup.string().when('namespace', { is: CREATE_NAMESPACE_KEY, - then: yup - .string() - .matches( - projectNameRegex, - "Name must consist of lower case alphanumeric characters or '-' and must start and end with an alphanumeric character.", - ) - .required('Required'), + then: (schema) => + schema + .matches( + projectNameRegex, + "Name must consist of lower case alphanumeric characters or '-' and must start and end with an alphanumeric character.", + ) + .required('Required'), }); export const advancedOptionsValidationSchema = yup.object().shape({ diff --git a/frontend/public/components/configmaps/configmap-utils.ts b/frontend/public/components/configmaps/configmap-utils.ts index 6206b85186d..55ecc0f66a3 100644 --- a/frontend/public/components/configmaps/configmap-utils.ts +++ b/frontend/public/components/configmaps/configmap-utils.ts @@ -197,7 +197,7 @@ const formDataSchema = (values: ConfigMapFormInitialValues) => export const validationSchema = () => yup.mixed().test({ - test(values: ConfigMapFormInitialValues) { + async test(values: ConfigMapFormInitialValues) { const formYamlDefinition = yup.object({ editorType: yup .string() @@ -205,14 +205,15 @@ export const validationSchema = () => .required(i18next.t('public~Required')), formData: yup.mixed().when('editorType', { is: EditorType.Form, - then: formDataSchema(values), + then: (schema) => schema.concat(formDataSchema(values)), }), yamlData: yup.mixed().when('editorType', { is: EditorType.YAML, - then: yup.string().required(i18next.t('public~Required')), + then: (schema) => schema.concat(yup.string().required(i18next.t('public~Required'))), }), }); - return formYamlDefinition.validate(values, { abortEarly: false }); + await formYamlDefinition.validate(values, { abortEarly: false }); + return true; }, }); diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 372016ea4d6..037effea695 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -8788,11 +8788,6 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.0.tgz#55122b6536ea496b4b44893ee2608141d10d9916" integrity sha512-R+H8IZclI8AAkSBRQJLVOsxwAoHd6WC40b4QTNWIjzAa6BXOBfQcM587MXDTVPeYaopFNWHUFLx7eNmHDSxMWg== -fn-name@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7" - integrity sha1-UhTXU3pNBqSjAcDMJi/rhBiAAuc= - focus-trap@7.6.4: version "7.6.4" resolved "https://registry.yarnpkg.com/focus-trap/-/focus-trap-7.6.4.tgz#455ec5c51fee5ae99604ca15142409ffbbf84db9" @@ -14625,12 +14620,7 @@ propagate@^2.0.0: resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== -property-expr@^1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-1.5.1.tgz#22e8706894a0c8e28d58735804f6ba3a3673314f" - integrity sha512-CGuc0VUTGthpJXL36ydB6jnbyOf/rAHFvmVrJlH+Rg0DqqLFQGAP6hIaxD/G0OAmBJPhXDHuEJigrp0e0wFV6g== - -property-expr@^2.0.4: +property-expr@^2.0.4, property-expr@^2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8" integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== @@ -17109,11 +17099,6 @@ symlink-or-copy@^1.1.8, symlink-or-copy@^1.2.0, symlink-or-copy@^1.3.1: resolved "https://registry.yarnpkg.com/symlink-or-copy/-/symlink-or-copy-1.3.1.tgz#9506dd64d8e98fa21dcbf4018d1eab23e77f71fe" integrity sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA== -synchronous-promise@^2.0.6: - version "2.0.9" - resolved "https://registry.yarnpkg.com/synchronous-promise/-/synchronous-promise-2.0.9.tgz#b83db98e9e7ae826bf9c8261fd8ac859126c780a" - integrity sha512-LO95GIW16x69LuND1nuuwM4pjgFGupg7pZ/4lU86AmchPKrhk0o2tpMU2unXRrqo81iAFe1YJ0nAGEVwsrZAgg== - syntax-error@^1.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" @@ -17319,6 +17304,11 @@ timers-browserify@^2.0.12: dependencies: setimmediate "^1.0.4" +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-case/-/tiny-case-1.0.3.tgz#d980d66bc72b5d5a9ca86fb7c9ffdb9c898ddd03" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + tiny-glob@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.6.tgz#9e056e169d9788fe8a734dfa1ff02e9b92ed7eda" @@ -17636,6 +17626,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + type-fest@^4.18.2: version "4.27.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.27.0.tgz#57329aae32e7b27b942b961e3ef861f0873c4b1b" @@ -19352,18 +19347,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -yup@^0.27.0: - version "0.27.0" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.27.0.tgz#f8cb198c8e7dd2124beddc2457571329096b06e7" - integrity sha512-v1yFnE4+u9za42gG/b/081E7uNW9mUj3qtkmelLbW5YPROZzSH/KUUyJu9Wt8vxFJcT9otL/eZopS0YK1L5yPQ== - dependencies: - "@babel/runtime" "^7.0.0" - fn-name "~2.0.1" - lodash "^4.17.11" - property-expr "^1.5.0" - synchronous-promise "^2.0.6" - toposort "^2.0.2" - yup@^0.32.11: version "0.32.11" resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" @@ -19377,6 +19360,16 @@ yup@^0.32.11: property-expr "^2.0.4" toposort "^2.0.2" +yup@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/yup/-/yup-1.7.1.tgz#4c47c6bb367df08d4bc597f8c4c4f5fc4277f6ab" + integrity sha512-GKHFX2nXul2/4Dtfxhozv701jLQHdf6J34YDh2cEkpqoo8le5Mg6/LrdseVLrFarmFygZTlfIhHx/QKfb/QWXw== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" + zen-observable-ts@^0.8.21: version "0.8.21" resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.8.21.tgz#85d0031fbbde1eba3cd07d3ba90da241215f421d" From 87ede5635fc593a4e8a6638f2b941467bbd2d0fb Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Tue, 18 Nov 2025 11:53:10 -0500 Subject: [PATCH 2/6] Fixed build test failures --- .../src/components/import/validation-schema.ts | 16 +++++++++++----- .../project-access-form-validation-utils.spec.ts | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/packages/dev-console/src/components/import/validation-schema.ts b/frontend/packages/dev-console/src/components/import/validation-schema.ts index d0c1006c3dd..17e13b96cf8 100644 --- a/frontend/packages/dev-console/src/components/import/validation-schema.ts +++ b/frontend/packages/dev-console/src/components/import/validation-schema.ts @@ -216,12 +216,13 @@ export const limitsValidationSchema = (t: TFunction) => cpu: yup.object().shape({ request: yup .number() + .nullable() .transform((request) => (_.isNaN(request) ? undefined : request)) .min(0, t('devconsole~Request must be greater than or equal to 0.')) .test({ test(request) { const { requestUnit, limit, limitUnit } = this.parent; - if (limit !== undefined) { + if (limit !== undefined && limit !== null) { return ( convertToBaseValue(`${request}${requestUnit}`) <= convertToBaseValue(`${limit}${limitUnit}`) @@ -235,12 +236,13 @@ export const limitsValidationSchema = (t: TFunction) => limitUnit: yup.string().ensure(), limit: yup .number() + .nullable() .transform((limit) => (_.isNaN(limit) ? undefined : limit)) .min(0, t('devconsole~Limit must be greater than or equal to 0.')) .test({ test(limit) { const { request, requestUnit, limitUnit } = this.parent; - if (limit !== undefined) { + if (limit !== undefined && limit !== null) { return ( convertToBaseValue(`${limit}${limitUnit}`) >= convertToBaseValue(`${request}${requestUnit}`) @@ -254,12 +256,13 @@ export const limitsValidationSchema = (t: TFunction) => memory: yup.object().shape({ request: yup .number() + .nullable() .transform((request) => (_.isNaN(request) ? undefined : request)) .min(0, t('devconsole~Request must be greater than or equal to 0.')) .test({ test(request) { const { requestUnit, limit, limitUnit } = this.parent; - if (limit !== undefined) { + if (limit !== undefined && limit !== null) { return ( convertToBaseValue(`${request}${requestUnit}`) <= convertToBaseValue(`${limit}${limitUnit}`) @@ -272,12 +275,13 @@ export const limitsValidationSchema = (t: TFunction) => requestUnit: yup.string(), limit: yup .number() + .nullable() .transform((limit) => (_.isNaN(limit) ? undefined : limit)) .min(0, t('devconsole~Limit must be greater than or equal to 0.')) .test({ test(limit) { const { request, requestUnit, limitUnit } = this.parent; - if (limit !== undefined) { + if (limit !== undefined && limit !== null) { return ( convertToBaseValue(`${request}${requestUnit}`) <= convertToBaseValue(`${limit}${limitUnit}`) @@ -357,7 +361,9 @@ export const isiValidationSchema = (t: TFunction) => name: yup.string().required(t('devconsole~Required')), image: yup.object().required(t('devconsole~Required')), tag: yup.string(), - status: yup.string().required(t('devconsole~Required')), + status: yup.object().shape({ + status: yup.string().required(t('devconsole~Required')), + }), }); export const importFlowPipelineTemplateValidationSchema = yup diff --git a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts index 55bcd857447..b4d49cb1a33 100644 --- a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts +++ b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts @@ -10,7 +10,7 @@ describe('ValidationUtils', () => { await validationSchema.isValid(mockData).then((valid) => expect(valid).toEqual(false)); await validationSchema.validate(mockData).catch((err) => { expect(err.message).toBe('Required'); - expect(err.type).toBe('required'); + expect(err.type).toBe('optionality'); }); }); From ea4f0661e8b1411f5bfcf50cde96261201232e56 Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Tue, 18 Nov 2025 12:28:54 -0500 Subject: [PATCH 3/6] i18n fixes --- frontend/packages/dev-console/locales/en/devconsole.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/frontend/packages/dev-console/locales/en/devconsole.json b/frontend/packages/dev-console/locales/en/devconsole.json index 63d13714d38..33217a21b08 100644 --- a/frontend/packages/dev-console/locales/en/devconsole.json +++ b/frontend/packages/dev-console/locales/en/devconsole.json @@ -607,11 +607,9 @@ "Port must be between 1 and 65535.": "Port must be between 1 and 65535.", "Request must be greater than or equal to 0.": "Request must be greater than or equal to 0.", "CPU request must be less than or equal to limit.": "CPU request must be less than or equal to limit.", - "Unit must be millicores or cores.": "Unit must be millicores or cores.", "Limit must be greater than or equal to 0.": "Limit must be greater than or equal to 0.", "CPU limit must be greater than or equal to request.": "CPU limit must be greater than or equal to request.", "Memory request must be less than or equal to limit.": "Memory request must be less than or equal to limit.", - "Unit must be Mi or Gi.": "Unit must be Mi or Gi.", "Memory limit must be greater than or equal to request.": "Memory limit must be greater than or equal to request.", "Please enter a URL that is less then 2000 characters.": "Please enter a URL that is less then 2000 characters.", "Invalid Git URL.": "Invalid Git URL.", From addd201cd27162e7c7a71f6896d44253f021086c Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Tue, 18 Nov 2025 18:04:37 -0500 Subject: [PATCH 4/6] replaced nameRegex with bitBucketUserNameRegex, err.type required, subject.name --- .../project-access/__tests__/project-access-form-data.ts | 5 ++++- .../__tests__/project-access-form-validation-utils.spec.ts | 4 ++-- .../src/components/repository/repository-form-utils.ts | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-data.ts b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-data.ts index 114f985641a..9a9a1d43d02 100644 --- a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-data.ts +++ b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-data.ts @@ -3,7 +3,10 @@ import { UserRoleBinding, RoleBinding } from '../project-access-form-utils-types export const mockProjectAccessData = { projectAccess: [ { - user: 'abc', + subject: { + name: 'abc', + kind: 'User', + }, role: 'view', }, ], diff --git a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts index b4d49cb1a33..819ec946782 100644 --- a/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts +++ b/frontend/packages/dev-console/src/components/project-access/__tests__/project-access-form-validation-utils.spec.ts @@ -5,12 +5,12 @@ import { mockProjectAccessData } from './project-access-form-data'; describe('ValidationUtils', () => { it('should throw an error if Name field is empty', async () => { const mockData = cloneDeep(mockProjectAccessData); - mockData.projectAccess[0].user = ''; + mockData.projectAccess[0].subject.name = ''; await validationSchema.isValid(mockData).then((valid) => expect(valid).toEqual(false)); await validationSchema.validate(mockData).catch((err) => { expect(err.message).toBe('Required'); - expect(err.type).toBe('optionality'); + expect(err.type).toBe('required'); }); }); diff --git a/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts b/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts index ab1c66ba3c5..22e0bb14b14 100644 --- a/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts +++ b/frontend/packages/pipelines-plugin/src/components/repository/repository-form-utils.ts @@ -83,9 +83,9 @@ export const pipelinesAccessTokenValidationSchema = (t: TFunction) => schema.shape({ user: yup .string() - .matches(nameRegex, { + .matches(bitBucketUserNameRegex, { message: t( - 'pipelines-plugin~Name must consist of lower-case letters, numbers and hyphens. It must start with a letter and end with a letter or number.', + 'pipelines-plugin~Name must consist of lower-case letters, numbers, underscores and hyphens. It must start with a letter and end with a letter or number.', ), excludeEmptyString: true, }) From 1f6b216c40f92db41da3e62dfe1394c1c9b0eeb7 Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Thu, 20 Nov 2025 12:06:57 -0500 Subject: [PATCH 5/6] e2e test failure --- .../src/components/import/deployImage-validation-utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts b/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts index d40089af1d8..d5e217f43c2 100644 --- a/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts +++ b/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts @@ -18,7 +18,10 @@ export const deployValidationSchema = (t: TFunction) => project: projectNameValidationSchema, application: applicationNameValidationSchema, name: nameValidationSchema(t), - isi: isiValidationSchema(t), + isi: yup.object().when('registry', { + is: 'internal', + then: (schema) => schema.concat(isiValidationSchema(t)), + }), serverless: serverlessValidationSchema(t), deployment: deploymentValidationSchema(t), route: routeValidationSchema(t), From c1e58004e74136b7c200abe12c7e3b5315cdfcfe Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Thu, 20 Nov 2025 13:11:16 -0500 Subject: [PATCH 6/6] switching to original callback style --- .../src/components/import/deployImage-validation-utils.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts b/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts index d5e217f43c2..56ce186c259 100644 --- a/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts +++ b/frontend/packages/dev-console/src/components/import/deployImage-validation-utils.ts @@ -18,9 +18,8 @@ export const deployValidationSchema = (t: TFunction) => project: projectNameValidationSchema, application: applicationNameValidationSchema, name: nameValidationSchema(t), - isi: yup.object().when('registry', { - is: 'internal', - then: (schema) => schema.concat(isiValidationSchema(t)), + isi: yup.object().when('registry', ([registry], schema) => { + return registry === 'internal' ? schema.concat(isiValidationSchema(t)) : schema; }), serverless: serverlessValidationSchema(t), deployment: deploymentValidationSchema(t),