Commit 8219c379 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Validate the form before submission

Ensure we validate when the submit button is clicked
but before we submit the request
parent a9243d6f
......@@ -88,20 +88,16 @@ export const validateStage = (fields) => {
if (fields?.name) {
if (fields.name.length > NAME_MAX_LENGTH) {
newErrors.name = [ERRORS.MAX_LENGTH];
} else {
newErrors.name =
fields?.custom && DEFAULT_STAGE_NAMES.includes(fields.name.toLowerCase())
? [ERRORS.STAGE_NAME_EXISTS]
: [];
}
if (fields?.custom && DEFAULT_STAGE_NAMES.includes(fields.name.toLowerCase())) {
newErrors.name = [ERRORS.STAGE_NAME_EXISTS];
}
} else {
newErrors.name = [ERRORS.STAGE_NAME_MIN_LENGTH];
}
if (fields?.startEventIdentifier) {
if (fields?.endEventIdentifier) {
newErrors.endEventIdentifier = [];
} else {
if (!fields?.endEventIdentifier) {
newErrors.endEventIdentifier = [ERRORS.END_EVENT_REQUIRED];
}
} else {
......
<script>
import Vue from 'vue';
import { mapGetters, mapState } from 'vuex';
import { isEqual } from 'lodash';
import {
......@@ -163,7 +164,7 @@ export default {
this.fields.startEventIdentifier && this.eventMismatchError
? [ERRORS.INVALID_EVENT_PAIRS]
: newErrors.endEventIdentifier;
this.errors = { ...this.errors, ...newErrors };
Vue.set(this, 'errors', newErrors);
},
},
I18N,
......
......@@ -3,6 +3,7 @@ import Vue from 'vue';
import { GlButton, GlForm, GlFormInput, GlFormGroup, GlFormRadioGroup, GlModal } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { sprintf } from '~/locale';
import { convertObjectPropsToSnakeCase } from '~/lib/utils/common_utils';
import { swapArrayItems } from '~/lib/utils/array_utility';
import {
DEFAULT_STAGE_CONFIG,
......@@ -22,45 +23,20 @@ const findStageIndexByName = (stages, target = '') =>
const initializeStageErrors = (selectedPreset = PRESET_OPTIONS_DEFAULT) =>
selectedPreset === PRESET_OPTIONS_DEFAULT ? DEFAULT_STAGE_CONFIG.map(() => ({})) : [{}];
// Not great, we're mixing types
// better to make everything arrays 🤔
const maybeFirstElem = (arr = null) => {
if (Array.isArray(arr)) {
return arr.length ? arr[0] : null;
}
return arr || null;
};
const initializeStages = (selectedPreset = PRESET_OPTIONS_DEFAULT) =>
selectedPreset === PRESET_OPTIONS_DEFAULT
? DEFAULT_STAGE_CONFIG
: [{ ...defaultCustomStageFields }];
// TODO: move to utils
const formatStageData = (stages) => {
return stages
.filter(({ hidden = false }) => !hidden)
.map(
({
startEventIdentifier,
endEventIdentifier,
startEventLabelId,
endEventLabelId,
custom = false,
name,
...rest
}) => {
const additionalProps = custom
? {
start_event_identifier: maybeFirstElem(startEventIdentifier),
end_event_identifier: maybeFirstElem(endEventIdentifier),
start_event_label_id: maybeFirstElem(startEventLabelId),
end_event_label_id: maybeFirstElem(endEventLabelId),
}
: {};
return {
...rest,
...additionalProps,
custom,
name,
};
},
);
const formatStageDataForSubmission = (stages) => {
return stages.map(({ custom = false, name, ...rest }) => {
const additionalProps = custom ? convertObjectPropsToSnakeCase({ ...rest }) : {};
return {
...additionalProps,
custom,
name,
};
});
};
export default {
......@@ -102,10 +78,7 @@ export default {
const { name: nameError = [], stages: stageErrors = [{}] } = initialFormErrors;
const additionalFields = hasExtendedFormFields
? {
stages:
initialPreset === PRESET_OPTIONS_DEFAULT
? DEFAULT_STAGE_CONFIG
: [{ ...defaultCustomStageFields }],
stages: initializeStages(initialPreset),
stageErrors: stageErrors || initializeStageErrors(initialPreset),
...initialData,
}
......@@ -128,7 +101,7 @@ export default {
isValueStreamNameValid() {
return !this.nameError?.length;
},
invalidFeedback() {
invalidNameFeedback() {
return this.nameError?.length ? this.nameError.join('\n\n') : null;
},
hasInitialFormErrors() {
......@@ -160,6 +133,11 @@ export default {
activeStages() {
return this.stages.filter((stage) => !stage.hidden);
},
hasFormErrors() {
return Boolean(
this.nameError.length || this.stageErrors.some((obj) => Object.keys(obj).length),
);
},
},
watch: {
initialFormErrors({ name: nameError, stages: stageErrors }) {
......@@ -170,19 +148,20 @@ export default {
methods: {
...mapActions(['createValueStream']),
onSubmit() {
const { name, stages } = this;
console.log('onSubmit::this.nameError', this.nameError);
console.log('onSubmit::this.stageErrors', this.stageErrors);
// TODO: validate before submission
this.validate();
if (this.hasFormErrors) return false;
return this.createValueStream({
name,
stages: formatStageData(stages),
name: this.name,
stages: formatStageDataForSubmission(this.stages),
}).then(() => {
if (!this.hasInitialFormErrors) {
this.$toast.show(sprintf(this.$options.I18N.FORM_CREATED, { name }), {
this.$toast.show(sprintf(this.$options.I18N.FORM_CREATED, { name: this.name }), {
position: 'top-center',
});
this.name = '';
this.nameError = [];
this.stages = initializeStages(this.selectedPreset);
this.stageErrors = initializeStageErrors(this.selectedPreset);
}
});
},
......@@ -287,7 +266,7 @@ export default {
data-testid="create-value-stream-name"
label-for="create-value-stream-name"
:label="$options.I18N.FORM_FIELD_NAME_LABEL"
:invalid-feedback="invalidFeedback"
:invalid-feedback="invalidNameFeedback"
:state="isValueStreamNameValid"
>
<div class="gl-display-flex gl-justify-content-space-between">
......
......@@ -133,7 +133,7 @@ describe('CustomStageForm', () => {
it('clears the error when the field changes', async () => {
await setNameField('not an issue');
expect(findFieldErrors('name')).not.toContain('Stage name already exists');
expect(findFieldErrors('name')).toBeUndefined();
});
});
});
......
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