Commit 7256e544 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Correctly display form field errors

Fix correctly initialize edit form data

Ensures we initialize the form with values
when we are editing correctly

Minor fixup mutation specs
parent 6fbee9fa
......@@ -14,7 +14,7 @@ import {
getLabelEventsIdentifiers,
} from '../utils';
const initFields = {
const defaultFields = {
id: null,
name: null,
startEventIdentifier: null,
......@@ -58,18 +58,22 @@ export default {
errors: {
type: Object,
required: false,
default: null,
default: () => {},
},
},
data() {
return {
fields: {
...initFields,
...this.initialFields,
},
labelEvents: getLabelEventsIdentifiers(this.events),
fields: {},
};
},
computed: {
defaultFieldData() {
return {
...defaultFields,
...this.initialFields,
};
},
startEventOptions() {
return [
{ value: null, text: s__('CustomCycleAnalytics|Select start event') },
......@@ -118,7 +122,7 @@ export default {
);
},
isDirty() {
return !isEqual(this.initialFields, this.fields) && !isEqual(initFields, this.fields);
return !isEqual(this.initialFields, this.fields) && !isEqual(defaultFields, this.fields);
},
hasValidStartAndEndEventPair() {
const {
......@@ -147,14 +151,26 @@ export default {
},
},
mounted() {
this.labelEvents = getLabelEventsIdentifiers(this.events);
this.resetFormFields();
},
// updated() {
// this.resetFormFields();
// },
methods: {
resetFormFields() {
this.fields = this.defaultFieldData;
// console.log('this.fields', this.fields);
// console.log('this.initialFields', this.initialFields);
// console.log('defaultFields', defaultFields);
// Object.entries(this.defaultFieldData).
// for (let [key, value] of Object.entries(this.defaultFieldData)) {
// // console.log('setting', key, value);
// this.$set(this.fields, key, value);
// }
// console.log('this.fields', this.fields);
},
handleCancel() {
this.fields = {
...initFields,
...this.initialFields,
};
this.resetFormFields();
this.$emit('cancel');
},
handleSave() {
......@@ -245,7 +261,7 @@ export default {
!hasStartEvent ? s__('CustomCycleAnalytics|Please select a start event first') : ''
"
:state="isValid('endEventIdentifier')"
:invalid-feedback="fieldErrors('endEventIdentifier')"
:invalid-feedback="fieldErrors('endEventIdentifier') || endEventError"
>
<!-- :state="hasValidStartAndEndEventPair"
:invalid-feedback="endEventError" -->
......
......@@ -66,7 +66,7 @@ export default {
customStageFormErrors: {
type: Object,
required: false,
default: null,
default: () => {},
},
labels: {
type: Array,
......
......@@ -241,18 +241,16 @@ export const clearCustomStageFormErrors = ({ commit }) =>
export const requestCreateCustomStage = ({ commit }) => commit(types.REQUEST_CREATE_CUSTOM_STAGE);
export const receiveCreateCustomStageSuccess = ({ commit, dispatch }, { data: { title } }) => {
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE);
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS);
createFlash(__(`Your custom stage '${title}' was created`), 'notice');
return dispatch('fetchGroupStagesAndEvents').then(() => dispatch('fetchSummaryData'));
};
export const receiveCreateCustomStageError = ({ commit }, { status, message, errors, data }) => {
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_RESPONSE, { status, message, errors, data });
commit(types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR, { status, message, errors, data });
const { name } = data;
// TODO: check for 403, 422 etc
// Follow up issue to investigate https://gitlab.com/gitlab-org/gitlab/issues/36685
const flashMessage =
status !== httpStatus.UNPROCESSABLE_ENTITY
? __(`'${name}' stage already exists'`)
......@@ -322,7 +320,7 @@ export const fetchTasksByTypeData = ({ dispatch, state, getters }) => {
export const requestUpdateStage = ({ commit }) => commit(types.REQUEST_UPDATE_STAGE);
export const receiveUpdateStageSuccess = ({ commit, dispatch }, updatedData) => {
commit(types.RECEIVE_UPDATE_STAGE_RESPONSE);
commit(types.RECEIVE_UPDATE_STAGE_SUCCESS);
createFlash(__('Stage data updated'), 'notice');
dispatch('fetchGroupStagesAndEvents');
......@@ -333,7 +331,7 @@ export const receiveUpdateStageError = (
{ commit },
{ error: { response: { status = 400, data: errorData } = {} } = {}, data },
) => {
commit(types.RECEIVE_UPDATE_STAGE_RESPONSE);
commit(types.RECEIVE_UPDATE_STAGE_ERROR);
const ERROR_NAME_RESERVED = 'is reserved';
let message = __('There was a problem saving your custom stage, please try again');
......
......@@ -48,7 +48,8 @@ export const RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS = 'RECEIVE_CREATE_CUSTOM_STAGE_
export const RECEIVE_CREATE_CUSTOM_STAGE_ERROR = 'RECEIVE_CREATE_CUSTOM_STAGE_ERROR';
export const REQUEST_UPDATE_STAGE = 'REQUEST_UPDATE_STAGE';
export const RECEIVE_UPDATE_STAGE_RESPONSE = 'RECEIVE_UPDATE_STAGE_RESPONSE';
export const RECEIVE_UPDATE_STAGE_SUCCESS = 'RECEIVE_UPDATE_STAGE_SUCCESS';
export const RECEIVE_UPDATE_STAGE_ERROR = 'RECEIVE_UPDATE_STAGE_ERROR';
export const REQUEST_REMOVE_STAGE = 'REQUEST_REMOVE_STAGE';
export const RECEIVE_REMOVE_STAGE_RESPONSE = 'RECEIVE_REMOVE_STAGE_RESPONSE';
......
......@@ -96,18 +96,15 @@ export default {
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isCreatingCustomStage = true;
state.customStageFormInitData = {};
state.isEditingCustomStage = false;
},
[types.EDIT_CUSTOM_STAGE](state) {
state.isEditingCustomStage = true;
state.isCreatingCustomStage = false;
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isEditingCustomStage = false;
state.isCreatingCustomStage = false;
state.customStageFormInitData = {};
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isCreatingCustomStage = true;
},
[types.CLEAR_CUSTOM_STAGE_FORM_ERRORS](state) {
state.customStageFormErrors = null;
......@@ -155,20 +152,31 @@ export default {
},
[types.REQUEST_CREATE_CUSTOM_STAGE](state) {
state.isSavingCustomStage = true;
state.customStageFormErrors = {};
},
[types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR](state, { errors = null }) {
[types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR](state, { errors = null } = {}) {
state.isSavingCustomStage = false;
state.customStageFormErrors = errors;
state.customStageFormErrors = convertObjectPropsToCamelCase(errors, { deep: true });
},
[types.RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS](state) {
state.isSavingCustomStage = false;
state.customStageFormErrors = {};
},
[types.REQUEST_UPDATE_STAGE](state) {
state.isLoading = true;
state.isSavingCustomStage = true;
state.customStageFormErrors = {};
},
[types.RECEIVE_UPDATE_STAGE_SUCCESS](state) {
state.isLoading = false;
state.isSavingCustomStage = false;
state.isEditingCustomStage = false;
state.customStageFormErrors = {};
},
[types.RECEIVE_UPDATE_STAGE_RESPONSE](state) {
[types.RECEIVE_UPDATE_STAGE_ERROR](state, { errors = null } = {}) {
state.isLoading = false;
state.isSavingCustomStage = false;
state.customStageFormErrors = convertObjectPropsToCamelCase(errors, { deep: true });
},
[types.REQUEST_REMOVE_STAGE](state) {
state.isLoading = true;
......
......@@ -31,7 +31,7 @@ export default () => ({
medians: {},
customStageFormEvents: [],
customStageFormErrors: null,
customStageFormErrors: {},
tasksByType: {
subject: TASKS_BY_TYPE_SUBJECT_ISSUE,
......
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import { shallowMount, mount } from '@vue/test-utils';
import CustomStageForm from 'ee/analytics/cycle_analytics/components/custom_stage_form.vue';
import { STAGE_ACTIONS } from 'ee/analytics/cycle_analytics/constants';
import {
......@@ -21,11 +21,14 @@ const initData = {
};
describe('CustomStageForm', () => {
function createComponent(props) {
return mount(CustomStageForm, {
function createComponent(props, shallow = false) {
const func = shallow ? shallowMount : mount;
return func(CustomStageForm, {
propsData: {
events,
labels: groupLabels,
errors: {},
initialFields: {},
...props,
},
});
......@@ -248,7 +251,7 @@ describe('CustomStageForm', () => {
describe('with a stop event selected and a change to the start event', () => {
beforeEach(() => {
wrapper = createComponent({}, false);
wrapper = createComponent({});
wrapper.setData({
fields: {
......@@ -299,7 +302,7 @@ describe('CustomStageForm', () => {
describe('Stop event label', () => {
beforeEach(() => {
wrapper = createComponent({}, false);
wrapper = createComponent({});
});
afterEach(() => {
......@@ -353,15 +356,22 @@ describe('CustomStageForm', () => {
});
});
describe('Add stage button', () => {
beforeEach(() => {
wrapper = createComponent({}, false);
describe.only('Add stage button', () => {
beforeEach(done => {
wrapper = createComponent({}, true);
selectDropdownOption(wrapper, sel.startEvent, 1);
return Vue.nextTick(() => {
wrapper.vm
.$nextTick()
.then(() => {
selectDropdownOption(wrapper, sel.endEvent, 1);
return Vue.nextTick();
})
.then(wrapper.vm.$nextTick)
.then(done)
.catch(err => {
console.log('ERRRRRRR', err);
done.fail();
});
});
......@@ -369,8 +379,9 @@ describe('CustomStageForm', () => {
wrapper.destroy();
});
it('has text `Add stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Add stage');
it.only('has text `Add stage`', () => {
const txt = wrapper.find(sel.submit).text();
expect(txt).toEqual('Add stage');
});
it('is enabled when all required fields are filled', done => {
......@@ -391,7 +402,7 @@ describe('CustomStageForm', () => {
const stopEventIndex = 1;
beforeEach(() => {
wrapper = createComponent({}, false);
wrapper = createComponent({});
selectDropdownOption(wrapper, sel.startEvent, startEventDropdownIndex);
......@@ -452,7 +463,7 @@ describe('CustomStageForm', () => {
describe('Cancel button', () => {
beforeEach(() => {
wrapper = createComponent({}, false);
wrapper = createComponent({});
});
afterEach(() => {
......
......@@ -54,11 +54,18 @@ describe('Cycle analytics mutations', () => {
${types.REQUEST_CREATE_CUSTOM_STAGE} | ${'isSavingCustomStage'} | ${true}
${types.RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS} | ${'isSavingCustomStage'} | ${false}
${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'isSavingCustomStage'} | ${false}
${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'customStageFormErrors'} | ${{ errors: [] }}
${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'customStageFormErrors'} | ${{}}
${types.REQUEST_TASKS_BY_TYPE_DATA} | ${'isLoadingTasksByTypeChart'} | ${true}
${types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR} | ${'isLoadingTasksByTypeChart'} | ${false}
${types.REQUEST_UPDATE_STAGE} | ${'isLoading'} | ${true}
${types.RECEIVE_UPDATE_STAGE_RESPONSE} | ${'isLoading'} | ${false}
${types.REQUEST_UPDATE_STAGE} | ${'isSavingCustomStage'} | ${true}
${types.REQUEST_UPDATE_STAGE} | ${'customStageFormErrors'} | ${{}}
${types.RECEIVE_UPDATE_STAGE_SUCCESS} | ${'isLoading'} | ${false}
${types.RECEIVE_UPDATE_STAGE_SUCCESS} | ${'isSavingCustomStage'} | ${false}
${types.RECEIVE_UPDATE_STAGE_SUCCESS} | ${'isEditingCustomStage'} | ${false}
${types.RECEIVE_UPDATE_STAGE_SUCCESS} | ${'customStageFormErrors'} | ${{}}
${types.RECEIVE_UPDATE_STAGE_ERROR} | ${'isLoading'} | ${false}
${types.RECEIVE_UPDATE_STAGE_ERROR} | ${'isSavingCustomStage'} | ${false}
${types.REQUEST_REMOVE_STAGE} | ${'isLoading'} | ${true}
${types.RECEIVE_REMOVE_STAGE_RESPONSE} | ${'isLoading'} | ${false}
${types.REQUEST_DURATION_DATA} | ${'isLoadingDurationChart'} | ${true}
......@@ -118,6 +125,18 @@ describe('Cycle analytics mutations', () => {
});
});
describe(`types.RECEIVE_UPDATE_STAGE_ERROR`, () => {
const mockFormError = { errors: { start_identifier: ['Cant be blank'] } };
it('will set customStageFormErrors', () => {
state = {};
mutations[types.RECEIVE_UPDATE_STAGE_ERROR](state, mockFormError);
expect(state.customStageFormErrors).toEqual(
convertObjectPropsToCamelCase(mockFormError.errors),
);
});
});
describe.each`
mutation | value
${types.REQUEST_GROUP_LABELS} | ${[]}
......
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