Commit c5e19ab9 authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch '325820-update-validation-trigger' into 'master'

Update triggering validation on the alerts integration form

See merge request gitlab-org/gitlab!57697
parents f87d8eda 4d098a9d
...@@ -223,6 +223,10 @@ export default { ...@@ -223,6 +223,10 @@ export default {
testAlertModal() { testAlertModal() {
return this.isFormDirty ? testAlertModalId : null; return this.isFormDirty ? testAlertModalId : null;
}, },
prometheusUrlInvalidFeedback() {
const { blankUrlError, invalidUrlError } = i18n.integrationFormSteps.prometheusFormUrl;
return this.integrationForm.apiUrl?.length ? invalidUrlError : blankUrlError;
},
}, },
watch: { watch: {
tabIndex(val) { tabIndex(val) {
...@@ -288,6 +292,9 @@ export default { ...@@ -288,6 +292,9 @@ export default {
if (this.isHttp) { if (this.isHttp) {
this.validationState.apiUrl = true; this.validationState.apiUrl = true;
this.validateName(); this.validateName();
if (!this.validationState.name) {
this.$refs.integrationName.$el.scrollIntoView({ behavior: 'smooth', block: 'center' });
}
} else if (this.isPrometheus) { } else if (this.isPrometheus) {
this.validationState.name = true; this.validationState.name = true;
this.validateApiUrl(); this.validateApiUrl();
...@@ -300,6 +307,11 @@ export default { ...@@ -300,6 +307,11 @@ export default {
this.$emit('save-and-test-alert-payload', this.dataForSave, this.testAlertPayload); this.$emit('save-and-test-alert-payload', this.dataForSave, this.testAlertPayload);
}, },
submit(testAfterSubmit = false) { submit(testAfterSubmit = false) {
this.triggerValidation();
if (!this.isFormValid) {
return;
}
const event = this.currentIntegration ? 'update-integration' : 'create-new-integration'; const event = this.currentIntegration ? 'update-integration' : 'create-new-integration';
this.$emit(event, this.dataForSave, testAfterSubmit); this.$emit(event, this.dataForSave, testAfterSubmit);
}, },
...@@ -412,7 +424,6 @@ export default { ...@@ -412,7 +424,6 @@ export default {
:disabled="isSelectDisabled" :disabled="isSelectDisabled"
class="gl-max-w-full" class="gl-max-w-full"
:options="integrationTypesOptions" :options="integrationTypesOptions"
@change="triggerValidation"
/> />
<alert-settings-form-help-block <alert-settings-form-help-block
...@@ -439,6 +450,7 @@ export default { ...@@ -439,6 +450,7 @@ export default {
> >
<gl-form-input <gl-form-input
id="name-integration" id="name-integration"
ref="integrationName"
v-model="integrationForm.name" v-model="integrationForm.name"
type="text" type="text"
:placeholder="$options.i18n.integrationFormSteps.nameIntegration.placeholder" :placeholder="$options.i18n.integrationFormSteps.nameIntegration.placeholder"
...@@ -473,7 +485,7 @@ export default { ...@@ -473,7 +485,7 @@ export default {
class="gl-my-4" class="gl-my-4"
:label="$options.i18n.integrationFormSteps.prometheusFormUrl.label" :label="$options.i18n.integrationFormSteps.prometheusFormUrl.label"
label-for="api-url" label-for="api-url"
:invalid-feedback="$options.i18n.integrationFormSteps.prometheusFormUrl.error" :invalid-feedback="prometheusUrlInvalidFeedback"
:state="validationState.apiUrl" :state="validationState.apiUrl"
> >
<gl-form-input <gl-form-input
......
...@@ -70,7 +70,8 @@ export const i18n = { ...@@ -70,7 +70,8 @@ export const i18n = {
prometheusFormUrl: { prometheusFormUrl: {
label: s__('AlertSettings|Prometheus API base URL'), label: s__('AlertSettings|Prometheus API base URL'),
help: s__('AlertSettings|URL cannot be blank and must start with http or https'), help: s__('AlertSettings|URL cannot be blank and must start with http or https'),
error: s__('AlertSettings|URL is invalid.'), blankUrlError: __('URL cannot be blank'),
invalidUrlError: __('URL is invalid'),
}, },
restKeyInfo: { restKeyInfo: {
label: s__( label: s__(
......
---
title: Update validation trigger flow on the alerts integration form
merge_request: 57697
author:
type: changed
...@@ -3005,9 +3005,6 @@ msgstr "" ...@@ -3005,9 +3005,6 @@ msgstr ""
msgid "AlertSettings|URL cannot be blank and must start with http or https" msgid "AlertSettings|URL cannot be blank and must start with http or https"
msgstr "" msgstr ""
msgid "AlertSettings|URL is invalid."
msgstr ""
msgid "AlertSettings|Utilize the URL and authorization key below to authorize Prometheus to send alerts to GitLab. Review the Prometheus documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint." msgid "AlertSettings|Utilize the URL and authorization key below to authorize Prometheus to send alerts to GitLab. Review the Prometheus documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint."
msgstr "" msgstr ""
...@@ -32409,6 +32406,12 @@ msgstr "" ...@@ -32409,6 +32406,12 @@ msgstr ""
msgid "URL" msgid "URL"
msgstr "" msgstr ""
msgid "URL cannot be blank"
msgstr ""
msgid "URL is invalid"
msgstr ""
msgid "URL is required" msgid "URL is required"
msgstr "" msgstr ""
......
...@@ -10,6 +10,9 @@ import alertFields from '../mocks/alert_fields.json'; ...@@ -10,6 +10,9 @@ import alertFields from '../mocks/alert_fields.json';
import parsedMapping from '../mocks/parsed_mapping.json'; import parsedMapping from '../mocks/parsed_mapping.json';
import { defaultAlertSettingsConfig } from './util'; import { defaultAlertSettingsConfig } from './util';
const scrollIntoViewMock = jest.fn();
HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
describe('AlertsSettingsForm', () => { describe('AlertsSettingsForm', () => {
let wrapper; let wrapper;
const mockToastShow = jest.fn(); const mockToastShow = jest.fn();
...@@ -410,33 +413,35 @@ describe('AlertsSettingsForm', () => { ...@@ -410,33 +413,35 @@ describe('AlertsSettingsForm', () => {
createComponent(); createComponent();
}); });
it('should not be able to submit when no integration type is selected', () => { it('should not be able to submit when no integration type is selected', async () => {
selectOptionAtIndex(0); await selectOptionAtIndex(0);
expect(findSubmitButton().attributes('disabled')).toBe('disabled'); expect(findSubmitButton().attributes('disabled')).toBe('disabled');
}); });
it('should not be able to submit when HTTP integration form is invalid', () => { it('should not be able to submit when HTTP integration form is invalid', async () => {
selectOptionAtIndex(1); await selectOptionAtIndex(1);
await findFormFields().at(0).vm.$emit('input', '');
expect(findSubmitButton().attributes('disabled')).toBe('disabled'); expect(findSubmitButton().attributes('disabled')).toBe('disabled');
}); });
it('should be able to submit when HTTP integration form is valid', async () => { it('should be able to submit when HTTP integration form is valid', async () => {
await selectOptionAtIndex(1); await selectOptionAtIndex(1);
await findFormFields().at(0).setValue('Name'); await findFormFields().at(0).vm.$emit('input', 'Name');
expect(findSubmitButton().attributes('disabled')).toBe(undefined); expect(findSubmitButton().attributes('disabled')).toBe(undefined);
}); });
it('should not be able to submit when Prometheus integration form is invalid', () => { it('should not be able to submit when Prometheus integration form is invalid', async () => {
selectOptionAtIndex(2); await selectOptionAtIndex(2);
await findFormFields().at(0).vm.$emit('input', '');
expect(findSubmitButton().attributes('disabled')).toBe('disabled'); expect(findSubmitButton().attributes('disabled')).toBe('disabled');
}); });
it('should be able to submit when Prometheus integration form is valid', async () => { it('should be able to submit when Prometheus integration form is valid', async () => {
await selectOptionAtIndex(2); await selectOptionAtIndex(2);
await findFormFields().at(0).setValue('http://valid.url'); await findFormFields().at(0).vm.$emit('input', 'http://valid.url');
expect(findSubmitButton().attributes('disabled')).toBe(undefined); expect(findSubmitButton().attributes('disabled')).toBe(undefined);
}); });
...@@ -445,7 +450,7 @@ describe('AlertsSettingsForm', () => { ...@@ -445,7 +450,7 @@ describe('AlertsSettingsForm', () => {
currentIntegration: { type: typeSet.http, name: 'Existing integration' }, currentIntegration: { type: typeSet.http, name: 'Existing integration' },
}); });
await nextTick(); await nextTick();
await findFormFields().at(0).setValue('Updated name'); await findFormFields().at(0).vm.$emit('input', 'Updated name');
expect(findSubmitButton().attributes('disabled')).toBe(undefined); expect(findSubmitButton().attributes('disabled')).toBe(undefined);
}); });
...@@ -458,5 +463,20 @@ describe('AlertsSettingsForm', () => { ...@@ -458,5 +463,20 @@ describe('AlertsSettingsForm', () => {
expect(findSubmitButton().attributes('disabled')).toBe('disabled'); expect(findSubmitButton().attributes('disabled')).toBe('disabled');
}); });
it('should disable submit button after click on validation failure', async () => {
await selectOptionAtIndex(1);
findSubmitButton().trigger('click');
await nextTick();
expect(findSubmitButton().attributes('disabled')).toBe('disabled');
});
it('should scroll to invalid field on validation failure', async () => {
await selectOptionAtIndex(1);
findSubmitButton().trigger('click');
expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth', block: 'center' });
});
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment