diff --git a/electron/app/js/userSettings.js b/electron/app/js/userSettings.js
index ae224bd69..4cb528aa7 100644
--- a/electron/app/js/userSettings.js
+++ b/electron/app/js/userSettings.js
@@ -54,7 +54,8 @@ let _userSettingsFileName;
// "dividers": {
// "modelMain": 0.68,
// "modelRight": 0.48
-// }
+// },
+// "navCollapsed": true
// }
// }
//
@@ -185,7 +186,7 @@ function getDividerLocations() {
function setNavigationCollapsed(collapsed) {
const window = getOrCreateWindowSettings();
- window['navCollapsed'] = collapsed;
+ window['navCollapsed'] = Boolean(collapsed);
}
function getNavigationCollapsed() {
diff --git a/electron/app/locales/en/webui.json b/electron/app/locales/en/webui.json
index 3678c516a..60fff198c 100644
--- a/electron/app/locales/en/webui.json
+++ b/electron/app/locales/en/webui.json
@@ -566,6 +566,10 @@
"ingress-design-ingress-route-annotation-add-row": "Add Annotation",
"ingress-design-ingress-route-annotation-delete-row": "Delete Annotation",
+ "ingress-design-ingress-route-name-field-validation-error": "Route {{routeName}}",
+ "ingress-design-ingress-route-field-validation-error": "Route: {{routeName}}, Field: {{fieldName}}",
+ "ingress-design-ingress-route-field-tls-config-error": "The route {{routeName}} has the {{fieldName}} field enabled but the {{specifyTlsSecretFieldName}} field is disabled.",
+
"ingress-design-ingress-tls-secret-title": "TLS Secret for Ingress Routes",
"ingress-design-specify-tls-secret-label": "Use Ingress TLS Secret",
"ingress-design-specify-tls-secret-help": "To secure traffic to the ingress controller with TLS, specify the secret that contains the TLS private key and certificate. The Ingress resource only supports a single TLS port, 443, and assumes TLS termination at the ingress (traffic between the ingress and the service and its pods is in clear text).",
@@ -934,6 +938,8 @@
"validation-helper-ingress-annotation-hint": "Enter a valid annotation name value pair",
"validation-helper-ingress-annotation-message-detail": "The annotation ({{annotation}}) must be a name value pair separate by colon",
+ "validation-error-dialog-default-title": "Unknown action failed",
+
"vz-config-title": "Kubernetes Client Configuration for Verrazzano",
"vz-config-coming-soon": "Coming Soon...",
"vz-application-title": "Verrazzano Application",
diff --git a/webui/src/js/models/ingress-definition.js b/webui/src/js/models/ingress-definition.js
index 0ec2ee814..039e03453 100644
--- a/webui/src/js/models/ingress-definition.js
+++ b/webui/src/js/models/ingress-definition.js
@@ -34,6 +34,8 @@ define(['knockout', 'utils/observable-properties', 'utils/validation-helper'],
this.dockerRegSecretUserId = props.createProperty('').asCredential();
this.dockerRegSecretUserPwd = props.createProperty('').asCredential();
this.dockerRegSecretUserEmail = props.createProperty('');
+ this.dockerRegSecretUserEmail.addValidator(...validationHelper.getEmailAddressValidators());
+
this.createDockerRegSecret = props.createProperty(false);
this.specifyDockerRegSecret = props.createProperty(false);
this.specifyIngressTLSSecret = props.createProperty(false);
@@ -46,10 +48,11 @@ define(['knockout', 'utils/observable-properties', 'utils/validation-helper'],
this.opensslExecutableFilePath = props.createProperty(window.api.k8s.getOpenSSLFilePath());
- this.validators = { TargetPortValidator: validationHelper.getPortNumberValidators(),
+ this.validators = {
+ targetPortValidator: validationHelper.getPortNumberValidators(),
k8sNameValidator: validationHelper.getK8sNameValidators(),
- VirtualHostNameValidator: validationHelper.getHostNameValidators(),
- IngressPathValidator: validationHelper.getIngressPathValidators()
+ virtualHostNameValidator: validationHelper.getHostNameValidators(),
+ ingressPathValidator: validationHelper.getIngressPathValidators()
};
this.voyagerProvider = props.createProperty('OKE');
diff --git a/webui/src/js/utils/ingress-controller-installer.js b/webui/src/js/utils/ingress-controller-installer.js
index 033ed65af..ea551495c 100644
--- a/webui/src/js/utils/ingress-controller-installer.js
+++ b/webui/src/js/utils/ingress-controller-installer.js
@@ -228,7 +228,6 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
if (ingressControllerProvider === 'traefik' && dockerSecretName) {
args['deployment.imagePullSecrets[0].name'] = dockerSecretName;
}
-
if (ingressControllerProvider === 'traefik' || ingressControllerProvider === 'nginx') {
args['kubernetes.namespaces'] = '{' + ingressControllerNamespace + ',' + this.project.k8sDomain.kubernetesNamespace.value + '}';
}
@@ -256,13 +255,8 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
await window.api.ipc.invoke('show-error-message', errTitle, errMessage);
return Promise.resolve(false);
}
-
}
-
-
}
-
-
} catch(err) {
dialogHelper.closeBusyDialog();
throw err;
@@ -271,7 +265,6 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
}
};
-
this.getHelmOptions = () => {
const options = {};
if (this.project.kubectl.kubeConfig.value) {
@@ -303,40 +296,31 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
validationHelper.validateRequiredField(this.project.ingress.ingressControllerProvider.value));
if (this.project.ingress.installIngressController.value === true) {
-
validationObject.addField('ingress-design-ingress-namespace-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressControllerNamespace.value));
+ this.project.ingress.ingressControllerNamespace.validate(true));
validationObject.addField('ingress-design-ingress-name-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressControllerName.value));
+ this.project.ingress.ingressControllerName.validate(true));
const ingressControllerProvider = this.project.ingress.ingressControllerProvider.value;
-
if (ingressControllerProvider === 'traefik' || ingressControllerProvider === 'voyager' ) {
-
if (this.project.ingress.specifyDockerRegSecret.value === true) {
validationObject.addField('ingress-design-ingress-docker-reg-secret-name',
- validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretName.value));
- }
-
- if (this.project.ingress.createDockerRegSecret.value == true) {
- validationObject.addField('ingress-design-ingress-docker-reg-secret-useremail',
- validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretUserEmail.value));
- validationObject.addField('ingress-design-ingress-docker-reg-secret-useremail',
- validationHelper.validateEmailAddress(this.project.ingress.dockerRegSecretUserEmail.value));
- validationObject.addField('ingress-design-ingress-docker-reg-secret-userid',
- validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretUserId.value));
- validationObject.addField('ingress-design-ingress-docker-reg-secret-userpwd',
- validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretUserPwd.value));
+ this.project.ingress.dockerRegSecretName.validate(true));
+
+ if (this.project.ingress.createDockerRegSecret.value === true) {
+ validationObject.addField('ingress-design-ingress-docker-reg-secret-useremail',
+ this.project.ingress.dockerRegSecretUserEmail.validate(true));
+ validationObject.addField('ingress-design-ingress-docker-reg-secret-userid',
+ validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretUserId.value));
+ validationObject.addField('ingress-design-ingress-docker-reg-secret-userpwd',
+ validationHelper.validateRequiredField(this.project.ingress.dockerRegSecretUserPwd.value));
+ }
}
-
}
}
-
return validationObject;
};
-
}
-
return new IngressInstaller();
});
diff --git a/webui/src/js/utils/ingress-resource-generator.js b/webui/src/js/utils/ingress-resource-generator.js
index 5f88b4f35..c9d6c3487 100644
--- a/webui/src/js/utils/ingress-resource-generator.js
+++ b/webui/src/js/utils/ingress-resource-generator.js
@@ -19,15 +19,15 @@ define(['models/wkt-project', 'js-yaml'],
for (const route of this.project.ingress.ingressRoutes.value) {
switch (this.project.ingress.ingressControllerProvider.value) {
case 'voyager':
- ingressRouteData = this.createVoyagerRoutesAsYaml(route, this.project);
+ ingressRouteData = this.createVoyagerRoutesAsYaml(route);
break;
case 'traefik':
- ingressRouteData = this.createTraefikRoutesAsYaml(route, this.project);
+ ingressRouteData = this.createTraefikRoutesAsYaml(route);
break;
case 'nginx':
- ingressRouteData = this.createNginxRoutesAsYaml(route, this.project);
+ ingressRouteData = this.createNginxRoutesAsYaml(route);
break;
}
lines.push(ingressRouteData, '');
@@ -39,7 +39,7 @@ define(['models/wkt-project', 'js-yaml'],
return lines;
}
- createVoyagerRoutesAsYaml(item, wktProject) {
+ createVoyagerRoutesAsYaml(item) {
const namespace = item['targetServiceNameSpace'] || 'default';
const result = {
@@ -67,21 +67,21 @@ define(['models/wkt-project', 'js-yaml'],
]
}
};
- this.addTlsSpec(result, item, wktProject);
+ this.addTlsSpec(result, item);
this.addVirtualHost(result, item);
this.addAnnotations(result, item);
return jsYaml.dump(result);
}
- createNginxRoutesAsYaml(item, wktProject) {
- return this._createStandardRoutesAsYaml(item, wktProject);
+ createNginxRoutesAsYaml(item) {
+ return this._createStandardRoutesAsYaml(item);
}
- createTraefikRoutesAsYaml(item, wktProject) {
- return this._createStandardRoutesAsYaml(item, wktProject);
+ createTraefikRoutesAsYaml(item) {
+ return this._createStandardRoutesAsYaml(item);
}
- _createStandardRoutesAsYaml(item, wktProject) {
+ _createStandardRoutesAsYaml(item) {
const namespace = item['targetServiceNameSpace'] || 'default';
const result = {
@@ -114,16 +114,17 @@ define(['models/wkt-project', 'js-yaml'],
]
}
};
- this.addTlsSpec(result, item, wktProject);
+ this.addTlsSpec(result, item);
this.addVirtualHost(result, item);
this.addAnnotations(result, item);
return jsYaml.dump(result);
}
- addTlsSpec(result, item, wktProject) {
- if (item && item['tlsEnabled'] === true) {
+ addTlsSpec(result, item) {
+ // If the Ingress TLS secret is not enabled, do not add the ingress TLS secret name even if it exists.
+ if (this.project.ingress.specifyIngressTLSSecret.value && item && item['tlsEnabled'] === true) {
if (!item['tlsSecretName']) {
- item['tlsSecretName'] = wktProject.ingress.ingressTLSSecretName.value;
+ item['tlsSecretName'] = this.project.ingress.ingressTLSSecretName.value;
}
const obj = { secretName: item['tlsSecretName'] };
diff --git a/webui/src/js/utils/ingress-routes-helper.js b/webui/src/js/utils/ingress-routes-helper.js
index 3f9a7df9d..6fc436964 100644
--- a/webui/src/js/utils/ingress-routes-helper.js
+++ b/webui/src/js/utils/ingress-routes-helper.js
@@ -101,11 +101,11 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
// Best effort sanity check to see if ingress controller has been installed
// If user install their own ingress controller then we are not going to scan all namespaces for
// controller to verify it.
-
+ //
if (this.project.ingress.installIngressController.value === true) {
busyDialogMessage = i18n.t('ingress-installer-check-ingress-controller-service',
{});
- dialogHelper.updateBusyDialog(busyDialogMessage, 4 / totalSteps);
+ dialogHelper.updateBusyDialog(busyDialogMessage, 4/totalSteps);
let serviceName = '';
if (this.project.ingress.ingressControllerProvider.value === 'nginx') {
serviceName = this.project.ingress.ingressControllerName.value + '-ingress-nginx-controller';
@@ -116,21 +116,21 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
const result = await this.checkIngressControllerService(kubectlExe, serviceName,
this.project.ingress.ingressControllerNamespace.value, kubectlOptions);
if (!result.isSuccess) {
- const errMessage = i18n.t('ingress-installer-check-ingress-controller-service-not-installed',
- {error: result.reason,
- serviceName: serviceName,
- ingressControllerName: this.project.ingress.ingressControllerName.value,
- namespace: this.project.ingress.ingressControllerNamespace.value});
+ const errMessage = i18n.t('ingress-installer-check-ingress-controller-service-not-installed', {
+ error: result.reason,
+ serviceName: serviceName,
+ ingressControllerName: this.project.ingress.ingressControllerName.value,
+ namespace: this.project.ingress.ingressControllerNamespace.value
+ });
dialogHelper.closeBusyDialog();
await window.api.ipc.invoke('show-error-message', errTitle, errMessage);
return Promise.resolve(false);
}
}
-
if (this.project.ingress.createTLSSecret.value === true) {
busyDialogMessage = i18n.t('ingress-installer-create-tls-secret-in-progress', {});
- dialogHelper.updateBusyDialog(busyDialogMessage, 4 / totalSteps);
+ dialogHelper.updateBusyDialog(busyDialogMessage, 5/totalSteps);
let tlsKeyFile = 'tls1.key';
let tlsCertFile = 'tls1.crt';
@@ -150,15 +150,12 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
if (!certGenResults.isSuccess) {
const errMessage = i18n.t('ingress-installer-generate-tls-files-error-message',
- {
- error: certGenResults.reason
- });
+ { error: certGenResults.reason });
dialogHelper.closeBusyDialog();
await window.api.ipc.invoke('show-error-message', errTitle, errMessage);
return Promise.resolve(false);
}
}
-
} else {
tlsKeyFile = this.project.ingress.ingressTLSKeyFile.value;
tlsCertFile = this.project.ingress.ingressTLSCertFile.value;
@@ -268,7 +265,7 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
busyDialogMessage = i18n.t('ingress-installer-create-ingress-route-in-progress',
{ingressRoute: item['name']});
- dialogHelper.updateBusyDialog(busyDialogMessage, 5 / totalSteps);
+ dialogHelper.updateBusyDialog(busyDialogMessage, 6/totalSteps);
const ingressRouteResult = await (window.api.ipc.invoke('k8s-apply', kubectlExe, ingressRouteData,
kubectlOptions));
@@ -291,7 +288,6 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
item['accessPoint'] = 'Route has been created but cannot determine access point at the moment';
}
}
-
} else {
errTitle = i18n.t('ingress-installer-create-ingress-route-error-title');
const errMessage = i18n.t('ingress-installer-create-ingress-route-error-message',
@@ -299,21 +295,14 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
await window.api.ipc.invoke('show-error-message', errTitle, errMessage);
return Promise.resolve(false);
}
-
}
const title = i18n.t('ingress-installer-routes-update-complete-title');
const message = i18n.t('ingress-installer-routes-update-complete-message');
await window.api.ipc.invoke('show-info-message', title, message);
-
- dialogHelper.closeBusyDialog();
-
- } else {
- dialogHelper.closeBusyDialog();
}
-
} catch(err) {
dialogHelper.closeBusyDialog();
- throw err;
+ return Promise.reject(err);
} finally {
dialogHelper.closeBusyDialog();
}
@@ -336,68 +325,122 @@ function(project, wktConsole, k8sHelper, i18n, projectIo, dialogHelper, validati
validationObject.addField('ingress-design-ingress-provider-label',
validationHelper.validateRequiredField(this.project.ingress.ingressControllerProvider.value));
- const ingressRoutesArrayLength = this.project.ingress.ingressRoutes.value.length;
- let hasTLSRoutes = false;
- for (let i = 0; i < ingressRoutesArrayLength ; i++) {
- const item = this.project.ingress.ingressRoutes.value[i];
- if (item['tlsEnabled'] === true) {
- hasTLSRoutes = true;
- }
- this.checkIngressData(item, validationObject, settingsFormConfig);
- }
-
if (this.project.ingress.specifyIngressTLSSecret.value === true) {
validationObject.addField('ingress-design-tls-secret-name-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressTLSSecretName.value));
- }
+ this.project.ingress.ingressTLSSecretName.validate(true));
- if (this.project.ingress.createTLSSecret.value === true && this.project.ingress.generateTLSFiles.value === false) {
- validationObject.addField('ingress-design-ingress-tlskeyfile-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressTLSKeyFile.value));
- validationObject.addField('ingress-design-ingress-tlscertfile-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressTLSCertFile.value));
+ if (this.project.ingress.createTLSSecret.value === true) {
+ if (this.project.ingress.generateTLSFiles.value === true) {
+ validationObject.addField('ingress-design-openssl-exe-file-path-label',
+ validationHelper.validateRequiredField(this.project.ingress.opensslExecutableFilePath.value));
+ validationObject.addField('ingress-design-generate-tls-subject-label',
+ validationHelper.validateRequiredField(this.project.ingress.ingressTLSSubject.value));
+ } else {
+ validationObject.addField('ingress-design-ingress-tlskeyfile-label',
+ validationHelper.validateRequiredField(this.project.ingress.ingressTLSKeyFile.value));
+ validationObject.addField('ingress-design-ingress-tlscertfile-label',
+ validationHelper.validateRequiredField(this.project.ingress.ingressTLSCertFile.value));
+ }
+ }
}
- if (hasTLSRoutes) {
- validationObject.addField('ingress-design-tls-secret-name-label',
- validationHelper.validateRequiredField(this.project.ingress.ingressTLSSecretName.value));
+ const ingressRoutesArrayLength = this.project.ingress.ingressRoutes.value.length;
+ for (let i = 0; i < ingressRoutesArrayLength ; i++) {
+ const item = this.project.ingress.ingressRoutes.value[i];
+ this.checkIngressData(item, validationObject, this.project.ingress.specifyIngressTLSSecret.value);
}
return validationObject;
};
- this.checkTLSFileExists = async (file)=> {
- if (typeof file !== 'undefined' && file !== '') {
- const result = await window.api.ipc.invoke('verify-file-exists', file);
-
- if (result.isValid) {
- return Promise.resolve(true);
+ this.checkTLSFileExists = async (file) => {
+ return new Promise(resolve => {
+ if (file) {
+ window.api.ipc.invoke('verify-file-exists', file).then(result => {
+ if (result.isValid) {
+ resolve(true);
+ } else {
+ resolve(false);
+ }
+ });
} else {
- return Promise.resolve(false);
+ resolve(false);
}
- }
- return Promise.resolve(false);
+ });
};
- this.checkIngressData = (data, validationObject)=> {
- const items = ['name', 'targetServiceNameSpace', 'targetService', 'targetPort', 'path'];
+ this.checkIngressData = (data, validationObject, tlsSecretSpecified) => {
+ const routeConfig = validationObject.getDefaultConfigObject();
+ routeConfig.fieldNameIsKey = false;
+
+ const items = ['name', 'targetServiceNameSpace', 'targetService', 'targetPort', 'path', 'virtualHost'];
+ let errFieldMessage;
+
items.forEach(attribute => {
- let errFieldMessage = 'route name: ';
- if (attribute === 'targetServiceNameSpace') {
- errFieldMessage += data['name'] + ' ' + i18n.t('ingress-design-ingress-route-targetservicenamespace-label');
- }
- if (attribute === 'targetService') {
- errFieldMessage += data['name'] + ' ' + i18n.t('ingress-design-ingress-route-targetservice-label');
- }
- if (attribute === 'targetPort') {
- errFieldMessage += data['name'] + ' ' + i18n.t('ingress-design-ingress-route-targetport-label');
- }
- if (attribute === 'path') {
- errFieldMessage += data['name'] + ' ' + i18n.t('ingress-design-ingress-route-targetport-label');
- }
+ let validators;
+ let isRequired = true;
+ switch (attribute) {
+ case 'name':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-name-field-validation-error', { routeName: data['name'] });
+ validators = this.project.ingress.validators.k8sNameValidator;
+ break;
+
+ case 'targetServiceNameSpace':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-targetservicenamespace-label')
+ });
+ validators = this.project.ingress.validators.k8sNameValidator;
+ break;
+ case 'targetService':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-targetservice-label')
+ });
+ validators = this.project.ingress.validators.k8sNameValidator;
+ break;
+
+ case 'targetPort':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-targetport-label')
+ });
+ validators = this.project.ingress.validators.targetPortValidator;
+ break;
+
+ case 'path':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-path-label')
+ });
+ validators = this.project.ingress.validators.ingressPathValidator;
+ break;
+
+ case 'virtualHost':
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-virtualhost-label')
+ });
+ validators = this.project.ingress.validators.virtualHostNameValidator;
+ isRequired = false;
+ break;
+ }
validationObject.addField(errFieldMessage,
- validationHelper.validateRequiredField(data[attribute]));
+ validationHelper.validateField(validators, data[attribute], isRequired), routeConfig);
});
+
+ if (data['tlsEnabled'] && !tlsSecretSpecified) {
+ errFieldMessage = i18n.t('ingress-design-ingress-route-field-validation-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-tls-label')
+ });
+ const errMessage = i18n.t('ingress-design-ingress-route-field-tls-config-error', {
+ routeName: data['name'],
+ fieldName: i18n.t('ingress-design-ingress-route-tls-label'),
+ specifyTlsSecretFieldName: i18n.t('ingress-design-specify-tls-secret-label')
+ });
+ validationObject.addField(errFieldMessage, errMessage, routeConfig);
+ }
};
this.getHelmOptions = () => {
diff --git a/webui/src/js/utils/observable-properties.js b/webui/src/js/utils/observable-properties.js
index 31580d9ae..a91a33397 100644
--- a/webui/src/js/utils/observable-properties.js
+++ b/webui/src/js/utils/observable-properties.js
@@ -204,42 +204,7 @@ define(['knockout', 'utils/common-utilities', 'utils/validation-helper', 'utils/
}
validate(isRequired) {
- const currentValue = this.value;
- let errMessages = [];
-
- function toErrorMessage(err) {
- if (err instanceof Error) {
- return err.message;
- } else if (err instanceof String) {
- return err;
- } else {
- return err.toString();
- }
- }
-
- // Optional fields whose value is empty should not be validated.
- if (isRequired || (currentValue && currentValue.toString().length > 0)) {
- for (const validator of this._validators) {
- try {
- validator.validate(currentValue);
- } catch (err) {
- // Another option might be to try to get the hint, messageSummary, or messageDetail fields from the validator...
- errMessages.push(toErrorMessage(err));
- }
- }
- }
-
- if (isRequired) {
- const requiredMessage = validationHelper.validateRequiredField(currentValue);
- if (requiredMessage) {
- errMessages.push(requiredMessage);
- }
- }
-
- if (errMessages.length === 0) {
- errMessages = undefined;
- }
- return errMessages;
+ return validationHelper.validateField(this._validators, this.value, isRequired);
}
validators() {
diff --git a/webui/src/js/utils/validation-helper.js b/webui/src/js/utils/validation-helper.js
index abae0ecfe..5101c5eea 100644
--- a/webui/src/js/utils/validation-helper.js
+++ b/webui/src/js/utils/validation-helper.js
@@ -91,18 +91,21 @@ function(i18n, Validator, ojvalidationError, RegExpValidator, LengthValidator, N
return new ValidatableObject(flowName);
};
+ this.validateField = (validators, currentValue, isRequired = false) => {
+ return this._validateSpecialField(validators, currentValue, isRequired);
+ };
+
this.validateRequiredField = (currentValue) => {
- let requiredMessage;
- if (currentValue === undefined || currentValue === null) {
- requiredMessage = i18n.t('validation-helper-validate-field-value-is-not-defined');
- } else if (currentValue === '') {
- requiredMessage = i18n.t('validation-helper-validate-string-field-value-is-empty');
- } else if (Array.isArray(currentValue) && currentValue.length === 0) {
- requiredMessage = i18n.t('validation-helper-validate-array-field-value-is-empty');
- }
- return requiredMessage;
+ return _validateRequiredFieldValue(currentValue);
};
+ this.getRequiredFieldValidators = () => {
+ return [
+ {
+ validate: _validateRequiredFieldValue
+ }
+ ];
+ };
this.getK8sCpuValidators = () => {
return [
@@ -330,6 +333,18 @@ function(i18n, Validator, ojvalidationError, RegExpValidator, LengthValidator, N
return message;
}
+ function _validateRequiredFieldValue(value) {
+ let requiredMessage;
+ if (value === undefined || value === null) {
+ requiredMessage = i18n.t('validation-helper-validate-field-value-is-not-defined');
+ } else if (value === '') {
+ requiredMessage = i18n.t('validation-helper-validate-string-field-value-is-empty');
+ } else if (Array.isArray(value) && value.length === 0) {
+ requiredMessage = i18n.t('validation-helper-validate-array-field-value-is-empty');
+ }
+ return requiredMessage;
+ }
+
const K8S_CPU_REGEX = [ /^[1-9]\d*[Mm]?$/, /^\d+(\.\d{1,3})?$/, /^0\.\d{1,3}$/ ];
const K8S_CPU_HELP_URL = 'https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#meaning-of-cpu';
function _validateK8sCpuValue(value) {
diff --git a/webui/src/js/views/route-edit-dialog.html b/webui/src/js/views/route-edit-dialog.html
index db72cb1ec..ee045917b 100644
--- a/webui/src/js/views/route-edit-dialog.html
+++ b/webui/src/js/views/route-edit-dialog.html
@@ -20,12 +20,12 @@
+ validators="[[project.ingress.validators.virtualHostNameValidator]]">
+ validators="[[project.ingress.validators.ingressPathValidator]]">
+ value="{{targetService.observable}}"
+ validators="[[project.ingress.validators.k8sNameValidator]]">
+ validators="[[project.ingress.validators.targetPortValidator]]">