Commit 93af1114 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Wire create and edit form actions

Allows us to reuse the custom_stage_form
for both editing and creating a custom cycle
analytics stage.

Dispatch updateStage action

Added `id` field to edit form initial data

Display updated stage data after successful action
parent b4758cfa
......@@ -125,6 +125,7 @@ export default {
'removeStage',
'setFeatureFlags',
'editCustomStage',
'updateStage',
]),
onGroupSelect(group) {
this.setSelectedGroup(group);
......@@ -154,7 +155,7 @@ export default {
onCreateCustomStage(data) {
this.createCustomStage(data);
},
onUpdateStage(data) {
onUpdateCustomStage(data) {
this.updateStage(data);
},
onRemoveStage(id) {
......@@ -262,9 +263,10 @@ export default {
@selectStage="onStageSelect"
@editStage="onShowEditStageForm"
@showAddStageForm="onShowAddStageForm"
@submit="onCreateCustomStage"
@hideStage="onUpdateStage"
@hideStage="onUpdateCustomStage"
@removeStage="onRemoveStage"
@createStage="onCreateCustomStage"
@updateStage="onUpdateCustomStage"
/>
</div>
</div>
......
......@@ -15,6 +15,7 @@ import {
} from '../utils';
const initFields = {
id: null,
name: null,
startEventIdentifier: null,
startEventLabelId: null,
......@@ -132,7 +133,7 @@ export default {
},
saveStageText() {
return this.isEditingCustomStage
? s__('CustomCycleAnalytics|Edit stage')
? s__('CustomCycleAnalytics|Update stage')
: s__('CustomCycleAnalytics|Add stage');
},
formTitle() {
......@@ -150,10 +151,13 @@ export default {
this.$emit('cancel');
},
handleSave() {
this.$emit(
this.isEditingCustomStage ? STAGE_ACTIONS.EDIT : STAGE_ACTIONS.SAVE,
snakeFields(this.fields),
);
const data = snakeFields(this.fields);
if (this.isEditingCustomStage) {
const { id } = this.initialFields;
this.$emit(STAGE_ACTIONS.UPDATE, { ...data, id });
} else {
this.$emit(STAGE_ACTIONS.CREATE, data);
}
},
handleSelectLabel(key, labelId = null) {
this.fields[key] = labelId;
......@@ -184,7 +188,7 @@ export default {
<gl-form-group :label="s__('CustomCycleAnalytics|Start event')">
<gl-form-select
v-model="fields.startEventIdentifier"
name="add-stage-start-event"
name="custom-stage-start-event"
:required="true"
:options="startEventOptions"
/>
......@@ -195,7 +199,7 @@ export default {
<labels-selector
:labels="labels"
:selected-label-id="fields.startEventLabelId"
name="add-stage-start-event-label"
name="custom-stage-start-event-label"
@selectLabel="labelId => handleSelectLabel('startEventLabelId', labelId)"
@clearLabel="handleClearLabel('startEventLabelId')"
/>
......@@ -214,7 +218,7 @@ export default {
>
<gl-form-select
v-model="fields.endEventIdentifier"
name="add-stage-stop-event"
name="custom-stage-stop-event"
:options="endEventOptions"
:required="true"
:disabled="!hasStartEvent"
......@@ -226,7 +230,7 @@ export default {
<labels-selector
:labels="labels"
:selected-label-id="fields.endEventLabelId"
name="add-stage-stop-event-label"
name="custom-stage-stop-event-label"
@selectLabel="labelId => handleSelectLabel('endEventLabelId', labelId)"
@clearLabel="handleClearLabel('endEventLabelId')"
/>
......
......@@ -91,6 +91,9 @@ export default {
const { currentStageEvents = [], isLoading, isEmptyStage } = this;
return currentStageEvents.length && !isLoading && !isEmptyStage;
},
customStageFormActive() {
return this.isCreatingCustomStage;
},
stageHeaders() {
return [
{
......@@ -109,13 +112,13 @@ export default {
title: this.stageName,
description: __('The collection of events added to the data gathered for that stage.'),
classes: 'event-header pl-3',
displayHeader: !this.isAddingCustomStage,
displayHeader: !this.customStageFormActive,
},
{
title: __('Total Time'),
description: __('The time taken by each data entry gathered by that stage.'),
classes: 'total-time-header pr-5 text-right',
displayHeader: !this.isAddingCustomStage,
displayHeader: !this.customStageFormActive,
},
];
},
......@@ -129,6 +132,7 @@ export default {
this.$emit(STAGE_ACTIONS.REMOVE, stageId);
},
},
STAGE_ACTIONS,
};
</script>
<template>
......@@ -159,14 +163,14 @@ export default {
:is-active="!isCreatingCustomStage && stage.id === currentStage.id"
:can-edit="canEditStages"
:is-default-stage="!stage.custom"
@select="$emit('selectStage', stage)"
@remove="removeStage(stage.id)"
@hide="hideStage(stage.id)"
@edit="$emit(STAGE_ACTIONS.EDIT, stageData)"
@select="$emit($options.STAGE_ACTIONS.SELECT, stage)"
@edit="$emit($options.STAGE_ACTIONS.EDIT, stage)"
/>
<add-stage-button
v-if="canEditStages"
:active="isAddingCustomStage"
:active="customStageFormActive"
@showform="$emit('showAddStageForm')"
/>
</ul>
......@@ -181,7 +185,8 @@ export default {
:initial-fields="customStageFormInitData"
:is-editing-custom-stage="isEditingCustomStage"
@submit="$emit('submit', $event)"
@saveStage="saveStage"
@createStage="$emit($options.STAGE_ACTIONS.CREATE, $event)"
@updateStage="$emit($options.STAGE_ACTIONS.UPDATE, $event)"
/>
<template v-else>
<stage-event-list
......
......@@ -37,6 +37,7 @@ export const STAGE_ACTIONS = {
SELECT: 'selectStage',
EDIT: 'editStage',
REMOVE: 'removeStage',
SAVE: 'saveStage',
HIDE: 'hideStage',
CREATE: 'createStage',
UPDATE: 'updateStage',
};
......@@ -86,10 +86,12 @@ export const fetchCycleAnalyticsData = ({ dispatch }) => {
export const hideCustomStageForm = ({ commit }) => commit(types.HIDE_CUSTOM_STAGE_FORM);
export const showCustomStageForm = ({ commit }) => commit(types.SHOW_CUSTOM_STAGE_FORM);
export const editCustomStage = ({ commit, dispatch }, initData = {}) => {
commit(types.EDIT_CUSTOM_STAGE, initData);
if (initData.id) {
dispatch('setSelectedStageId', initData.id);
export const editCustomStage = ({ commit, dispatch }, selectedStage = {}) => {
commit(types.EDIT_CUSTOM_STAGE);
commit(types.SET_SELECTED_STAGE_DATA, selectedStage);
if (selectedStage.id) {
dispatch('setSelectedStageId', selectedStage.id);
}
};
......@@ -251,11 +253,12 @@ export const fetchTasksByTypeData = ({ dispatch, state, getters }) => {
};
export const requestUpdateStage = ({ commit }) => commit(types.REQUEST_UPDATE_STAGE);
export const receiveUpdateStageSuccess = ({ commit, dispatch }) => {
export const receiveUpdateStageSuccess = ({ commit, dispatch }, updatedData) => {
commit(types.RECEIVE_UPDATE_STAGE_RESPONSE);
createFlash(__(`Stage data updated`), 'notice');
dispatch('fetchGroupStagesAndEvents');
commit(types.SET_SELECTED_STAGE_DATA, updatedData);
};
export const receiveUpdateStageError = ({ commit }) => {
......
......@@ -19,6 +19,7 @@ export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR';
export const HIDE_CUSTOM_STAGE_FORM = 'HIDE_CUSTOM_STAGE_FORM';
export const SHOW_CUSTOM_STAGE_FORM = 'SHOW_CUSTOM_STAGE_FORM';
export const EDIT_CUSTOM_STAGE = 'EDIT_CUSTOM_STAGE';
export const SET_SELECTED_STAGE_DATA = 'SET_SELECTED_STAGE_DATA';
export const REQUEST_GROUP_LABELS = 'REQUEST_GROUP_LABELS';
export const RECEIVE_GROUP_LABELS_SUCCESS = 'RECEIVE_GROUP_LABELS_SUCCESS';
......
......@@ -80,19 +80,32 @@ export default {
state.isCreatingCustomStage = true;
state.customStageFormInitData = {};
},
[types.EDIT_CUSTOM_STAGE](state, initData) {
console.log('EDIT_CUSTOM_STAGE::initData', initData);
[types.EDIT_CUSTOM_STAGE](state) {
state.isEditingCustomStage = true;
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isEditingCustomStage = false;
state.isCreatingCustomStage = false;
state.customStageFormInitData = {};
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isCreatingCustomStage = true;
},
[types.SET_SELECTED_STAGE_DATA](state, initData) {
const data = convertObjectPropsToCamelCase(initData);
const {
title: name,
id,
title: name, // TODO: do we still need to do this?
startEventIdentifier,
endEventIdentifier,
startEventLabelId,
endEventLabelId,
} = initData;
} = data;
state.isEditingCustomStage = true;
// TODO: remove setSelectedStageId action in favour of passing the id into this + a getter
state.customStageFormInitData = {
...state.customStageFormInitData,
id,
name,
startEventIdentifier,
endEventIdentifier,
......@@ -100,14 +113,6 @@ export default {
endEventLabelId,
};
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isEditingCustomStage = false;
state.isCreatingCustomStage = false;
state.customStageFormInitData = {};
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = true;
},
[types.RECEIVE_SUMMARY_DATA_ERROR](state) {
state.summary = [];
},
......@@ -179,6 +184,7 @@ export default {
},
[types.RECEIVE_UPDATE_STAGE_RESPONSE](state) {
state.isLoading = false;
state.isSavingCustomStage = false;
},
[types.REQUEST_REMOVE_STAGE](state) {
state.isLoading = true;
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`CustomStageForm does not have a loading icon 1`] = `
"<button type=\\"button\\" class=\\"js-custom-stage-form-submit btn btn-success\\"><!---->
Add stage
exports[`CustomStageForm Editing a custom stage isSavingCustomStage=true displays a loading icon 1`] = `
"<button disabled=\\"disabled\\" type=\\"button\\" class=\\"js-save-stage btn btn-success\\"><span class=\\"gl-spinner-container\\"><span aria-label=\\"Loading\\" aria-hidden=\\"true\\" class=\\"gl-spinner gl-spinner-orange gl-spinner-sm\\"></span></span>
Update stage
</button>"
`;
exports[`CustomStageForm isSavingCustomStage=true displays a loading icon 1`] = `
"<button disabled=\\"disabled\\" type=\\"button\\" class=\\"js-custom-stage-form-submit btn btn-success\\"><span class=\\"gl-spinner-container\\"><span aria-label=\\"Loading\\" aria-hidden=\\"true\\" class=\\"gl-spinner gl-spinner-orange gl-spinner-sm\\"></span></span>
exports[`CustomStageForm Empty form isSavingCustomStage=true displays a loading icon 1`] = `
"<button disabled=\\"disabled\\" type=\\"button\\" class=\\"js-save-stage btn btn-success\\"><span class=\\"gl-spinner-container\\"><span aria-label=\\"Loading\\" aria-hidden=\\"true\\" class=\\"gl-spinner gl-spinner-orange gl-spinner-sm\\"></span></span>
Add stage
</button>"
`;
......@@ -12,6 +12,7 @@ import {
} from '../mock_data';
const initData = {
id: 74,
name: 'Cool stage pre',
startEventIdentifier: labelStartEvent.identifier,
startEventLabelId: groupLabels[0].id,
......@@ -35,11 +36,11 @@ describe('CustomStageForm', () => {
const findEvent = ev => wrapper.emitted()[ev];
const sel = {
name: '[name="add-stage-name"]',
startEvent: '[name="add-stage-start-event"]',
startEventLabel: '[name="add-stage-start-event-label"]',
endEvent: '[name="add-stage-stop-event"]',
endEventLabel: '[name="add-stage-stop-event-label"]',
name: '[name="custom-stage-name"]',
startEvent: '[name="custom-stage-start-event"]',
startEventLabel: '[name="custom-stage-start-event-label"]',
endEvent: '[name="custom-stage-stop-event"]',
endEventLabel: '[name="custom-stage-stop-event-label"]',
submit: '.js-save-stage',
cancel: '.js-save-stage-cancel',
invalidFeedback: '.invalid-feedback',
......@@ -360,7 +361,7 @@ describe('CustomStageForm', () => {
wrapper.destroy();
});
it('has text `Edit stage`', () => {
it('has text `Add stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Add stage');
});
......@@ -395,21 +396,25 @@ describe('CustomStageForm', () => {
wrapper.destroy();
});
it(`emits a ${STAGE_ACTIONS.SAVE} event when clicked`, () => {
let event = findEvent(STAGE_ACTIONS.SAVE);
it(`emits a ${STAGE_ACTIONS.CREATE} event when clicked`, done => {
let event = findEvent(STAGE_ACTIONS.CREATE);
expect(event).toBeUndefined();
wrapper.find(sel.submit).trigger('click');
event = findEvent(STAGE_ACTIONS.SAVE);
Vue.nextTick(() => {
event = findEvent(STAGE_ACTIONS.CREATE);
expect(event).toBeTruthy();
expect(event.length).toEqual(1);
done();
});
});
it('`submit` event receives the latest data', () => {
it(`${STAGE_ACTIONS.CREATE} event receives the latest data`, () => {
const startEv = startEvents[startEventIndex];
const selectedStopEvent = getDropdownOption(wrapper, sel.stopEvent, stopEventIndex);
let event = findEvent(STAGE_ACTIONS.SAVE);
let event = findEvent(STAGE_ACTIONS.CREATE);
expect(event).toBeUndefined();
const res = [
......@@ -423,7 +428,7 @@ describe('CustomStageForm', () => {
];
wrapper.find(sel.submit).trigger('click');
event = findEvent(STAGE_ACTIONS.SAVE);
event = findEvent(STAGE_ACTIONS.CREATE);
expect(event[0]).toEqual(res);
});
});
......@@ -464,6 +469,7 @@ describe('CustomStageForm', () => {
Vue.nextTick(() => {
expect(wrapper.vm.fields).toEqual({
id: null,
name: null,
startEventIdentifier: null,
startEventLabelId: null,
......@@ -497,6 +503,21 @@ describe('CustomStageForm', () => {
});
});
});
describe('isSavingCustomStage=true', () => {
beforeEach(() => {
wrapper = createComponent(
{
isSavingCustomStage: true,
},
false,
);
});
it('displays a loading icon', () => {
expect(wrapper.find(sel.submit).html()).toMatchSnapshot();
});
});
});
describe('Editing a custom stage', () => {
......@@ -547,9 +568,9 @@ describe('CustomStageForm', () => {
});
});
describe('Edit stage button', () => {
it('has text `Edit stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Edit stage');
describe('Update stage button', () => {
it('has text `Update stage`', () => {
expect(wrapper.find(sel.submit).text('value')).toEqual('Update stage');
});
it('is disabled by default', () => {
......@@ -632,16 +653,15 @@ describe('CustomStageForm', () => {
});
});
});
});
it('does not have a loading icon', () => {
expect(wrapper.find(sel.submit).html()).toMatchSnapshot();
});
describe('isSavingCustomStage=true', () => {
beforeEach(() => {
wrapper = createComponent(
{
isEditingCustomStage: true,
initialFields: {
...initData,
},
isSavingCustomStage: true,
},
false,
......@@ -652,4 +672,5 @@ describe('CustomStageForm', () => {
expect(wrapper.find(sel.submit).html()).toMatchSnapshot();
});
});
});
});
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