Commit 3f75c17e authored by Brandon Labuschagne's avatar Brandon Labuschagne

Merge branch '323984-vsa-remove-custom-stages-module' into 'master'

Removes the VSA customStages vuex module

See merge request gitlab-org/gitlab!61878
parents 9db77bf6 dacd825e
...@@ -63,9 +63,6 @@ export default { ...@@ -63,9 +63,6 @@ export default {
'selectedValueStream', 'selectedValueStream',
'pagination', 'pagination',
]), ]),
// NOTE: formEvents are fetched in the same request as the list of stages (fetchGroupStagesAndEvents)
// so i think its ok to bind formEvents here even though its only used as a prop to the custom-stage-form
...mapState('customStages', ['isCreatingCustomStage', 'formEvents']),
...mapGetters([ ...mapGetters([
'hasNoAccessError', 'hasNoAccessError',
'currentGroupPath', 'currentGroupPath',
...@@ -77,7 +74,6 @@ export default { ...@@ -77,7 +74,6 @@ export default {
'isOverviewStageSelected', 'isOverviewStageSelected',
'selectedStageCount', 'selectedStageCount',
]), ]),
...mapGetters('customStages', ['customStageFormActive']),
shouldRenderEmptyState() { shouldRenderEmptyState() {
return !this.currentGroup && !this.isLoading; return !this.currentGroup && !this.isLoading;
}, },
...@@ -119,7 +115,6 @@ export default { ...@@ -119,7 +115,6 @@ export default {
}; };
}, },
}, },
methods: { methods: {
...mapActions([ ...mapActions([
'fetchCycleAnalyticsData', 'fetchCycleAnalyticsData',
...@@ -128,18 +123,13 @@ export default { ...@@ -128,18 +123,13 @@ export default {
'setSelectedStage', 'setSelectedStage',
'setDefaultSelectedStage', 'setDefaultSelectedStage',
'setDateRange', 'setDateRange',
'removeStage',
'updateStage',
'reorderStage',
'updateStageTablePagination', 'updateStageTablePagination',
]), ]),
...mapActions('customStages', ['hideForm', 'showCreateForm', 'showEditForm', 'createStage']),
onProjectsSelect(projects) { onProjectsSelect(projects) {
this.setSelectedProjects(projects); this.setSelectedProjects(projects);
this.fetchCycleAnalyticsData(); this.fetchCycleAnalyticsData();
}, },
onStageSelect(stage) { onStageSelect(stage) {
this.hideForm();
if (stage.slug === OVERVIEW_STAGE_ID) { if (stage.slug === OVERVIEW_STAGE_ID) {
this.setDefaultSelectedStage(); this.setDefaultSelectedStage();
} else { } else {
...@@ -147,25 +137,6 @@ export default { ...@@ -147,25 +137,6 @@ export default {
this.fetchStageData(stage.slug); this.fetchStageData(stage.slug);
} }
}, },
onShowAddStageForm() {
this.showCreateForm();
},
onShowEditStageForm(initData = {}) {
this.setSelectedStage(initData);
this.showEditForm(initData);
},
onCreateCustomStage(data) {
this.createStage(data);
},
onUpdateCustomStage(data) {
this.updateStage(data);
},
onRemoveStage(id) {
this.removeStage(id);
},
onStageReorder(data) {
this.reorderStage(data);
},
onHandleUpdatePagination(data) { onHandleUpdatePagination(data) {
this.updateStageTablePagination(data); this.updateStageTablePagination(data);
}, },
......
...@@ -93,8 +93,7 @@ export default { ...@@ -93,8 +93,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState({ isCreating: 'isCreatingValueStream' }), ...mapState({ isCreating: 'isCreatingValueStream', formEvents: 'formEvents' }),
...mapState('customStages', ['formEvents']),
isValueStreamNameValid() { isValueStreamNameValid() {
return !this.nameError?.length; return !this.nameError?.length;
}, },
......
...@@ -2,12 +2,11 @@ import Api from 'ee/api'; ...@@ -2,12 +2,11 @@ import Api from 'ee/api';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils'; import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { __, sprintf } from '~/locale'; import { __ } from '~/locale';
import { FETCH_VALUE_STREAM_DATA, OVERVIEW_STAGE_CONFIG } from '../constants'; import { FETCH_VALUE_STREAM_DATA, OVERVIEW_STAGE_CONFIG } from '../constants';
import { import {
removeFlash, removeFlash,
throwIfUserForbidden, throwIfUserForbidden,
isStageNameExistsError,
checkForDataError, checkForDataError,
flashErrorIfStatusNotOk, flashErrorIfStatusNotOk,
} from '../utils'; } from '../utils';
...@@ -215,7 +214,7 @@ export const setDefaultSelectedStage = ({ dispatch }) => ...@@ -215,7 +214,7 @@ export const setDefaultSelectedStage = ({ dispatch }) =>
export const receiveGroupStagesSuccess = ({ commit }, stages) => export const receiveGroupStagesSuccess = ({ commit }, stages) =>
commit(types.RECEIVE_GROUP_STAGES_SUCCESS, stages); commit(types.RECEIVE_GROUP_STAGES_SUCCESS, stages);
export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => { export const fetchGroupStagesAndEvents = ({ dispatch, commit, getters }) => {
const { const {
currentValueStreamId: valueStreamId, currentValueStreamId: valueStreamId,
currentGroupPath: groupId, currentGroupPath: groupId,
...@@ -223,7 +222,7 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => { ...@@ -223,7 +222,7 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => {
} = getters; } = getters;
dispatch('requestGroupStages'); dispatch('requestGroupStages');
dispatch('customStages/setStageEvents', []); commit(types.SET_STAGE_EVENTS, []);
return Api.cycleAnalyticsGroupStagesAndEvents({ return Api.cycleAnalyticsGroupStagesAndEvents({
groupId, groupId,
...@@ -235,7 +234,7 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => { ...@@ -235,7 +234,7 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => {
}) })
.then(({ data: { stages = [], events = [] } }) => { .then(({ data: { stages = [], events = [] } }) => {
dispatch('receiveGroupStagesSuccess', stages); dispatch('receiveGroupStagesSuccess', stages);
dispatch('customStages/setStageEvents', events); commit(types.SET_STAGE_EVENTS, events);
}) })
.catch((error) => { .catch((error) => {
throwIfUserForbidden(error); throwIfUserForbidden(error);
...@@ -243,89 +242,6 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => { ...@@ -243,89 +242,6 @@ export const fetchGroupStagesAndEvents = ({ dispatch, getters }) => {
}); });
}; };
export const requestUpdateStage = ({ commit }) => commit(types.REQUEST_UPDATE_STAGE);
export const receiveUpdateStageSuccess = ({ commit, dispatch }, updatedData) => {
commit(types.RECEIVE_UPDATE_STAGE_SUCCESS);
createFlash({
message: __('Stage data updated'),
type: 'notice',
});
return Promise.resolve()
.then(() => dispatch('fetchGroupStagesAndEvents'))
.then(() => dispatch('customStages/showEditForm', updatedData))
.catch(() => {
createFlash({
message: __('There was a problem refreshing the data, please try again'),
});
});
};
export const receiveUpdateStageError = (
{ commit, dispatch },
{ status, responseData: { errors = null } = {}, data = {} },
) => {
commit(types.RECEIVE_UPDATE_STAGE_ERROR, { errors, data });
const { name = null } = data;
const message =
name && isStageNameExistsError({ status, errors })
? sprintf(__(`'%{name}' stage already exists`), { name })
: __('There was a problem saving your custom stage, please try again');
createFlash({
message: __(message),
});
return dispatch('customStages/setStageFormErrors', errors);
};
export const updateStage = ({ dispatch, getters }, { id, ...params }) => {
const { currentGroupPath, currentValueStreamId } = getters;
dispatch('requestUpdateStage');
dispatch('customStages/setSavingCustomStage');
return Api.cycleAnalyticsUpdateStage({
groupId: currentGroupPath,
valueStreamId: currentValueStreamId,
stageId: id,
data: params,
})
.then(({ data }) => dispatch('receiveUpdateStageSuccess', data))
.catch(({ response: { status = httpStatus.BAD_REQUEST, data: responseData } = {} }) =>
dispatch('receiveUpdateStageError', { status, responseData, data: { id, ...params } }),
);
};
export const requestRemoveStage = ({ commit }) => commit(types.REQUEST_REMOVE_STAGE);
export const receiveRemoveStageSuccess = ({ commit, dispatch }) => {
commit(types.RECEIVE_REMOVE_STAGE_RESPONSE);
createFlash({
message: __('Stage removed'),
type: 'notice',
});
return dispatch('fetchCycleAnalyticsData');
};
export const receiveRemoveStageError = ({ commit }) => {
commit(types.RECEIVE_REMOVE_STAGE_RESPONSE);
createFlash({
message: __('There was an error removing your custom stage, please try again'),
});
};
export const removeStage = ({ dispatch, getters }, stageId) => {
const { currentGroupPath, currentValueStreamId } = getters;
dispatch('requestRemoveStage');
return Api.cycleAnalyticsRemoveStage({
groupId: currentGroupPath,
valueStreamId: currentValueStreamId,
stageId,
})
.then(() => dispatch('receiveRemoveStageSuccess'))
.catch((error) => dispatch('receiveRemoveStageError', error));
};
export const initializeCycleAnalyticsSuccess = ({ commit }) => export const initializeCycleAnalyticsSuccess = ({ commit }) =>
commit(types.INITIALIZE_VALUE_STREAM_SUCCESS); commit(types.INITIALIZE_VALUE_STREAM_SUCCESS);
...@@ -372,37 +288,6 @@ export const initializeCycleAnalytics = ({ dispatch, commit }, initialData = {}) ...@@ -372,37 +288,6 @@ export const initializeCycleAnalytics = ({ dispatch, commit }, initialData = {})
return dispatch('initializeCycleAnalyticsSuccess'); return dispatch('initializeCycleAnalyticsSuccess');
}; };
export const requestReorderStage = ({ commit }) => commit(types.REQUEST_REORDER_STAGE);
export const receiveReorderStageSuccess = ({ commit }) =>
commit(types.RECEIVE_REORDER_STAGE_SUCCESS);
export const receiveReorderStageError = ({ commit }) => {
commit(types.RECEIVE_REORDER_STAGE_ERROR);
createFlash({
message: __('There was an error updating the stage order. Please try reloading the page.'),
});
};
export const reorderStage = ({ dispatch, getters }, initialData) => {
dispatch('requestReorderStage');
const { currentGroupPath, currentValueStreamId } = getters;
const { id, moveAfterId, moveBeforeId } = initialData;
const params = moveAfterId ? { move_after_id: moveAfterId } : { move_before_id: moveBeforeId };
return Api.cycleAnalyticsUpdateStage({
groupId: currentGroupPath,
valueStreamId: currentValueStreamId,
stageId: id,
data: params,
})
.then(({ data }) => dispatch('receiveReorderStageSuccess', data))
.catch(({ response: { status = httpStatus.BAD_REQUEST, data: responseData } = {} }) =>
dispatch('receiveReorderStageError', { status, responseData }),
);
};
export const receiveCreateValueStreamSuccess = ({ commit, dispatch }, valueStream = {}) => { export const receiveCreateValueStreamSuccess = ({ commit, dispatch }, valueStream = {}) => {
commit(types.RECEIVE_CREATE_VALUE_STREAM_SUCCESS, valueStream); commit(types.RECEIVE_CREATE_VALUE_STREAM_SUCCESS, valueStream);
return dispatch('fetchCycleAnalyticsData'); return dispatch('fetchCycleAnalyticsData');
......
...@@ -3,7 +3,6 @@ import Vuex from 'vuex'; ...@@ -3,7 +3,6 @@ import Vuex from 'vuex';
import filters from '~/vue_shared/components/filtered_search_bar/store/modules/filters'; import filters from '~/vue_shared/components/filtered_search_bar/store/modules/filters';
import * as actions from './actions'; import * as actions from './actions';
import * as getters from './getters'; import * as getters from './getters';
import customStages from './modules/custom_stages/index';
import durationChart from './modules/duration_chart/index'; import durationChart from './modules/duration_chart/index';
import typeOfWork from './modules/type_of_work/index'; import typeOfWork from './modules/type_of_work/index';
import mutations from './mutations'; import mutations from './mutations';
...@@ -17,5 +16,5 @@ export default () => ...@@ -17,5 +16,5 @@ export default () =>
getters, getters,
mutations, mutations,
state, state,
modules: { customStages, durationChart, typeOfWork, filters }, modules: { durationChart, typeOfWork, filters },
}); });
import Api from 'ee/api';
import createFlash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status';
import { __, sprintf } from '~/locale';
import { removeFlash, isStageNameExistsError } from '../../../utils';
import * as types from './mutation_types';
export const setStageEvents = ({ commit }, data) => commit(types.SET_STAGE_EVENTS, data);
export const setStageFormErrors = ({ commit }, errors) =>
commit(types.SET_STAGE_FORM_ERRORS, errors);
export const hideForm = ({ commit }) => {
commit(types.HIDE_FORM);
removeFlash();
};
export const showCreateForm = ({ commit }) => {
commit(types.SET_LOADING);
commit(types.SET_FORM_INITIAL_DATA);
commit(types.SHOW_CREATE_FORM);
removeFlash();
};
export const showEditForm = ({ commit, dispatch }, selectedStage = {}) => {
commit(types.SET_LOADING);
commit(types.SET_FORM_INITIAL_DATA, selectedStage);
dispatch('setSelectedStage', selectedStage, { root: true });
dispatch('clearSavingCustomStage');
commit(types.SHOW_EDIT_FORM);
removeFlash();
};
export const clearFormErrors = ({ commit }) => {
commit(types.CLEAR_FORM_ERRORS);
removeFlash();
};
export const setSavingCustomStage = ({ commit }) => commit(types.SET_SAVING_CUSTOM_STAGE);
export const clearSavingCustomStage = ({ commit }) => commit(types.CLEAR_SAVING_CUSTOM_STAGE);
export const receiveCreateStageSuccess = ({ commit, dispatch }, { data: { title } }) => {
commit(types.RECEIVE_CREATE_STAGE_SUCCESS);
createFlash({
message: sprintf(__(`Your custom stage '%{title}' was created`), { title }),
type: 'notice',
});
return Promise.resolve()
.then(() => dispatch('fetchGroupStagesAndEvents', null, { root: true }))
.then(() => dispatch('clearSavingCustomStage'))
.catch(() => {
createFlash({
message: __('There was a problem refreshing the data, please try again'),
});
});
};
export const receiveCreateStageError = (
{ commit, dispatch },
{ status = httpStatusCodes.BAD_REQUEST, errors = {}, data = {} } = {},
) => {
commit(types.RECEIVE_CREATE_STAGE_ERROR);
const { name = null } = data;
const flashMessage =
name && isStageNameExistsError({ status, errors })
? sprintf(__(`'%{name}' stage already exists`), { name })
: __('There was a problem saving your custom stage, please try again');
createFlash({
message: flashMessage,
});
return dispatch('setStageFormErrors', errors);
};
export const createStage = ({ dispatch, rootGetters }, data) => {
const { currentGroupPath, currentValueStreamId } = rootGetters;
dispatch('clearFormErrors');
dispatch('setSavingCustomStage');
return Api.cycleAnalyticsCreateStage({
groupId: currentGroupPath,
valueStreamId: currentValueStreamId,
data,
})
.then((response) => {
const { status, data: responseData } = response;
return dispatch('receiveCreateStageSuccess', { status, data: responseData });
})
.catch(({ response } = {}) => {
const { data: { message, errors } = null, status = httpStatusCodes.BAD_REQUEST } = response;
dispatch('receiveCreateStageError', { data, message, errors, status });
});
};
export const customStageFormActive = ({ isCreatingCustomStage, isEditingCustomStage }) =>
Boolean(isCreatingCustomStage || isEditingCustomStage);
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
export default {
namespaced: true,
state,
mutations,
getters,
actions,
};
export const SET_LOADING = 'SET_LOADING';
export const SET_STAGE_EVENTS = 'SET_STAGE_EVENTS';
export const SET_STAGE_FORM_ERRORS = 'SET_STAGE_FORM_ERRORS';
export const SET_FORM_INITIAL_DATA = 'SET_FORM_INITIAL_DATA';
export const SET_SAVING_CUSTOM_STAGE = 'SET_SAVING_CUSTOM_STAGE';
export const CLEAR_SAVING_CUSTOM_STAGE = 'CLEAR_SAVING_CUSTOM_STAGE';
export const HIDE_FORM = 'HIDE_FORM';
export const SHOW_CREATE_FORM = 'SHOW_CREATE_FORM';
export const SHOW_EDIT_FORM = 'SHOW_EDIT_FORM';
export const CLEAR_FORM_ERRORS = 'CLEAR_FORM_ERRORS';
export const RECEIVE_CREATE_STAGE_SUCCESS = 'RECEIVE_CREATE_STAGE_SUCCESS';
export const RECEIVE_CREATE_STAGE_ERROR = 'RECEIVE_CREATE_STAGE_ERROR';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { transformRawStages } from '../../../utils';
import * as types from './mutation_types';
const extractFormFields = (rawStage = {}) => {
const [
{
id = null,
name = null,
startEventIdentifier = null,
startEventLabel: { id: startEventLabelId = null } = {},
endEventIdentifier = null,
endEventLabel: { id: endEventLabelId = null } = {},
},
] = transformRawStages([rawStage]);
return {
id,
name,
startEventIdentifier,
startEventLabelId,
endEventIdentifier,
endEventLabelId,
};
};
export default {
[types.SET_STAGE_EVENTS](state, data = []) {
state.formEvents = data.map((ev) => convertObjectPropsToCamelCase(ev, { deep: true }));
},
[types.SET_STAGE_FORM_ERRORS](state, errors) {
state.formErrors = convertObjectPropsToCamelCase(errors, { deep: true });
},
[types.SET_FORM_INITIAL_DATA](state, rawStageData = null) {
state.formInitialData = rawStageData ? extractFormFields(rawStageData) : null;
},
[types.SET_SAVING_CUSTOM_STAGE](state) {
state.isSavingCustomStage = true;
},
[types.SET_LOADING](state) {
state.isLoadingCustomStage = true;
},
[types.CLEAR_SAVING_CUSTOM_STAGE](state) {
state.isSavingCustomStage = false;
},
[types.SHOW_CREATE_FORM](state) {
state.isLoadingCustomStage = false;
state.isEditingCustomStage = false;
state.isCreatingCustomStage = true;
state.formInitialData = null;
state.formErrors = null;
},
[types.SHOW_EDIT_FORM](state) {
state.isLoadingCustomStage = false;
state.isCreatingCustomStage = false;
state.isEditingCustomStage = true;
state.formErrors = null;
},
[types.HIDE_FORM](state) {
state.isEditingCustomStage = false;
state.isCreatingCustomStage = false;
state.formInitialData = null;
state.formErrors = null;
},
[types.CLEAR_FORM_ERRORS](state) {
state.formErrors = null;
},
[types.RECEIVE_CREATE_STAGE_ERROR](state) {
state.isSavingCustomStage = false;
state.isCreatingCustomStage = false;
state.isEditingCustomStage = false;
},
[types.RECEIVE_CREATE_STAGE_SUCCESS](state) {
state.formErrors = null;
state.formInitialData = null;
},
};
export default () => ({
isLoadingCustomStage: false,
isSavingCustomStage: false,
isCreatingCustomStage: false,
isEditingCustomStage: false,
formEvents: [],
formErrors: null,
formInitialData: null,
});
...@@ -5,6 +5,7 @@ export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE'; ...@@ -5,6 +5,7 @@ export const SET_SELECTED_STAGE = 'SET_SELECTED_STAGE';
export const SET_DATE_RANGE = 'SET_DATE_RANGE'; export const SET_DATE_RANGE = 'SET_DATE_RANGE';
export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM'; export const SET_SELECTED_VALUE_STREAM = 'SET_SELECTED_VALUE_STREAM';
export const SET_PAGINATION = 'SET_PAGINATION'; export const SET_PAGINATION = 'SET_PAGINATION';
export const SET_STAGE_EVENTS = 'SET_STAGE_EVENTS';
export const REQUEST_VALUE_STREAM_DATA = 'REQUEST_VALUE_STREAM_DATA'; export const REQUEST_VALUE_STREAM_DATA = 'REQUEST_VALUE_STREAM_DATA';
export const RECEIVE_VALUE_STREAM_DATA_SUCCESS = 'RECEIVE_VALUE_STREAM_DATA_SUCCESS'; export const RECEIVE_VALUE_STREAM_DATA_SUCCESS = 'RECEIVE_VALUE_STREAM_DATA_SUCCESS';
...@@ -26,20 +27,9 @@ export const REQUEST_GROUP_STAGES = 'REQUEST_GROUP_STAGES'; ...@@ -26,20 +27,9 @@ export const REQUEST_GROUP_STAGES = 'REQUEST_GROUP_STAGES';
export const RECEIVE_GROUP_STAGES_SUCCESS = 'RECEIVE_GROUP_STAGES_SUCCESS'; export const RECEIVE_GROUP_STAGES_SUCCESS = 'RECEIVE_GROUP_STAGES_SUCCESS';
export const RECEIVE_GROUP_STAGES_ERROR = 'RECEIVE_GROUP_STAGES_ERROR'; export const RECEIVE_GROUP_STAGES_ERROR = 'RECEIVE_GROUP_STAGES_ERROR';
export const REQUEST_UPDATE_STAGE = 'REQUEST_UPDATE_STAGE';
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';
export const INITIALIZE_VSA = 'INITIALIZE_VSA'; export const INITIALIZE_VSA = 'INITIALIZE_VSA';
export const INITIALIZE_VALUE_STREAM_SUCCESS = 'INITIALIZE_VALUE_STREAM_SUCCESS'; export const INITIALIZE_VALUE_STREAM_SUCCESS = 'INITIALIZE_VALUE_STREAM_SUCCESS';
export const REQUEST_REORDER_STAGE = 'REQUEST_REORDER_STAGE';
export const RECEIVE_REORDER_STAGE_SUCCESS = 'RECEIVE_REORDER_STAGE_SUCCESS';
export const RECEIVE_REORDER_STAGE_ERROR = 'RECEIVE_REORDER_STAGE_ERROR';
export const REQUEST_CREATE_VALUE_STREAM = 'REQUEST_CREATE_VALUE_STREAM'; export const REQUEST_CREATE_VALUE_STREAM = 'REQUEST_CREATE_VALUE_STREAM';
export const RECEIVE_CREATE_VALUE_STREAM_SUCCESS = 'RECEIVE_CREATE_VALUE_STREAM_SUCCESS'; export const RECEIVE_CREATE_VALUE_STREAM_SUCCESS = 'RECEIVE_CREATE_VALUE_STREAM_SUCCESS';
export const RECEIVE_CREATE_VALUE_STREAM_ERROR = 'RECEIVE_CREATE_VALUE_STREAM_ERROR'; export const RECEIVE_CREATE_VALUE_STREAM_ERROR = 'RECEIVE_CREATE_VALUE_STREAM_ERROR';
......
...@@ -18,6 +18,9 @@ export default { ...@@ -18,6 +18,9 @@ export default {
state.startDate = startDate; state.startDate = startDate;
state.endDate = endDate; state.endDate = endDate;
}, },
[types.SET_STAGE_EVENTS](state, data = []) {
state.formEvents = data.map((ev) => convertObjectPropsToCamelCase(ev, { deep: true }));
},
[types.REQUEST_VALUE_STREAM_DATA](state) { [types.REQUEST_VALUE_STREAM_DATA](state) {
state.isLoading = true; state.isLoading = true;
}, },
...@@ -77,21 +80,6 @@ export default { ...@@ -77,21 +80,6 @@ export default {
[types.RECEIVE_GROUP_STAGES_SUCCESS](state, stages) { [types.RECEIVE_GROUP_STAGES_SUCCESS](state, stages) {
state.stages = transformRawStages(stages); state.stages = transformRawStages(stages);
}, },
[types.REQUEST_UPDATE_STAGE](state) {
state.isLoading = true;
},
[types.RECEIVE_UPDATE_STAGE_SUCCESS](state) {
state.isLoading = false;
},
[types.RECEIVE_UPDATE_STAGE_ERROR](state) {
state.isLoading = false;
},
[types.REQUEST_REMOVE_STAGE](state) {
state.isLoading = true;
},
[types.RECEIVE_REMOVE_STAGE_RESPONSE](state) {
state.isLoading = false;
},
[types.INITIALIZE_VSA]( [types.INITIALIZE_VSA](
state, state,
{ {
...@@ -121,18 +109,6 @@ export default { ...@@ -121,18 +109,6 @@ export default {
[types.INITIALIZE_VALUE_STREAM_SUCCESS](state) { [types.INITIALIZE_VALUE_STREAM_SUCCESS](state) {
state.isLoading = false; state.isLoading = false;
}, },
[types.REQUEST_REORDER_STAGE](state) {
state.isSavingStageOrder = true;
state.errorSavingStageOrder = false;
},
[types.RECEIVE_REORDER_STAGE_SUCCESS](state) {
state.isSavingStageOrder = false;
state.errorSavingStageOrder = false;
},
[types.RECEIVE_REORDER_STAGE_ERROR](state) {
state.isSavingStageOrder = false;
state.errorSavingStageOrder = true;
},
[types.REQUEST_CREATE_VALUE_STREAM](state) { [types.REQUEST_CREATE_VALUE_STREAM](state) {
state.isCreatingValueStream = true; state.isCreatingValueStream = true;
state.createValueStreamErrors = {}; state.createValueStreamErrors = {};
......
...@@ -12,9 +12,6 @@ export default () => ({ ...@@ -12,9 +12,6 @@ export default () => ({
errorCode: null, errorCode: null,
isSavingStageOrder: false,
errorSavingStageOrder: false,
currentGroup: null, currentGroup: null,
selectedProjects: [], selectedProjects: [],
selectedStage: null, selectedStage: null,
...@@ -31,6 +28,7 @@ export default () => ({ ...@@ -31,6 +28,7 @@ export default () => ({
deleteValueStreamError: null, deleteValueStreamError: null,
stages: [], stages: [],
formEvents: [],
selectedStageError: '', selectedStageError: '',
summary: [], summary: [],
medians: {}, medians: {},
......
...@@ -18,7 +18,6 @@ import { toYmd } from '../shared/utils'; ...@@ -18,7 +18,6 @@ import { toYmd } from '../shared/utils';
import { OVERVIEW_STAGE_ID } from './constants'; import { OVERVIEW_STAGE_ID } from './constants';
const EVENT_TYPE_LABEL = 'label'; const EVENT_TYPE_LABEL = 'label';
const ERROR_NAME_RESERVED = 'is reserved';
export const removeFlash = (type = 'alert') => { export const removeFlash = (type = 'alert') => {
const flashEl = document.querySelector(`.flash-${type}`); const flashEl = document.querySelector(`.flash-${type}`);
...@@ -358,9 +357,6 @@ export const throwIfUserForbidden = (error) => { ...@@ -358,9 +357,6 @@ export const throwIfUserForbidden = (error) => {
} }
}; };
export const isStageNameExistsError = ({ status, errors }) =>
status === httpStatus.UNPROCESSABLE_ENTITY && errors?.name?.includes(ERROR_NAME_RESERVED);
export const timeSummaryForPathNavigation = ({ seconds, hours, days, minutes, weeks, months }) => { export const timeSummaryForPathNavigation = ({ seconds, hours, days, minutes, weeks, months }) => {
if (months) { if (months) {
return sprintf(s__('ValueStreamAnalytics|%{value}M'), { return sprintf(s__('ValueStreamAnalytics|%{value}M'), {
......
...@@ -22,16 +22,8 @@ export default { ...@@ -22,16 +22,8 @@ export default {
cycleAnalyticsValueStreamsPath: '/groups/:id/-/analytics/value_stream_analytics/value_streams', cycleAnalyticsValueStreamsPath: '/groups/:id/-/analytics/value_stream_analytics/value_streams',
cycleAnalyticsValueStreamPath: cycleAnalyticsValueStreamPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id', '/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id',
cycleAnalyticsStageEventsPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id/records',
cycleAnalyticsStageMedianPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id/median',
cycleAnalyticsStageCountPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id/count',
cycleAnalyticsStagePath: cycleAnalyticsStagePath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id', '/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id',
cycleAnalyticsDurationChartPath:
'/groups/:id/-/analytics/value_stream_analytics/value_streams/:value_stream_id/stages/:stage_id/average_duration_chart',
cycleAnalyticsGroupLabelsPath: '/groups/:namespace_path/-/labels.json', cycleAnalyticsGroupLabelsPath: '/groups/:namespace_path/-/labels.json',
codeReviewAnalyticsPath: '/api/:version/analytics/code_review', codeReviewAnalyticsPath: '/api/:version/analytics/code_review',
groupActivityIssuesPath: '/api/:version/analytics/group_activity/issues_count', groupActivityIssuesPath: '/api/:version/analytics/group_activity/issues_count',
...@@ -172,40 +164,23 @@ export default { ...@@ -172,40 +164,23 @@ export default {
}, },
cycleAnalyticsStageEvents({ groupId, valueStreamId, stageId, params = {} }) { cycleAnalyticsStageEvents({ groupId, valueStreamId, stageId, params = {} }) {
const url = Api.buildUrl(this.cycleAnalyticsStageEventsPath) const stageBase = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
.replace(':id', groupId) const url = `${stageBase}/records`;
.replace(':value_stream_id', valueStreamId)
.replace(':stage_id', stageId);
return axios.get(url, { params }); return axios.get(url, { params });
}, },
cycleAnalyticsStageMedian({ groupId, valueStreamId, stageId, params = {} }) { cycleAnalyticsStageMedian({ groupId, valueStreamId, stageId, params = {} }) {
const url = Api.buildUrl(this.cycleAnalyticsStageMedianPath) const stageBase = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
.replace(':id', groupId) const url = `${stageBase}/median`;
.replace(':value_stream_id', valueStreamId)
.replace(':stage_id', stageId);
return axios.get(url, { params }); return axios.get(url, { params });
}, },
cycleAnalyticsStageCount({ groupId, valueStreamId, stageId, params = {} }) { cycleAnalyticsStageCount({ groupId, valueStreamId, stageId, params = {} }) {
const url = Api.buildUrl(this.cycleAnalyticsStageCountPath) const stageBase = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
.replace(':id', groupId) const url = `${stageBase}/count`;
.replace(':value_stream_id', valueStreamId)
.replace(':stage_id', stageId);
return axios.get(url, { params }); return axios.get(url, { params });
}, },
cycleAnalyticsCreateStage({ groupId, valueStreamId, data }) {
const url = Api.buildUrl(this.cycleAnalyticsGroupStagesAndEventsPath)
.replace(':id', groupId)
.replace(':value_stream_id', valueStreamId);
return axios.post(url, data);
},
cycleAnalyticsCreateValueStream(groupId, data) { cycleAnalyticsCreateValueStream(groupId, data) {
const url = Api.buildUrl(this.cycleAnalyticsValueStreamsPath).replace(':id', groupId); const url = Api.buildUrl(this.cycleAnalyticsValueStreamsPath).replace(':id', groupId);
return axios.post(url, data); return axios.post(url, data);
...@@ -237,27 +212,10 @@ export default { ...@@ -237,27 +212,10 @@ export default {
.replace(':stage_id', stageId); .replace(':stage_id', stageId);
}, },
cycleAnalyticsUpdateStage({ groupId, valueStreamId, stageId, data }) {
const url = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
return axios.put(url, data);
},
cycleAnalyticsRemoveStage({ groupId, valueStreamId, stageId }) {
const url = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
return axios.delete(url);
},
cycleAnalyticsDurationChart({ groupId, valueStreamId, stageId, params = {} }) { cycleAnalyticsDurationChart({ groupId, valueStreamId, stageId, params = {} }) {
const url = Api.buildUrl(this.cycleAnalyticsDurationChartPath) const stageBase = this.cycleAnalyticsStageUrl({ groupId, valueStreamId, stageId });
.replace(':id', groupId) const url = `${stageBase}/average_duration_chart`;
.replace(':value_stream_id', valueStreamId) return axios.get(url, { params });
.replace(':stage_id', stageId);
return axios.get(url, {
params,
});
}, },
cycleAnalyticsGroupLabels(groupId, params = { search: null }) { cycleAnalyticsGroupLabels(groupId, params = { search: null }) {
......
...@@ -48,19 +48,12 @@ describe('ValueStreamForm', () => { ...@@ -48,19 +48,12 @@ describe('ValueStreamForm', () => {
new Vuex.Store({ new Vuex.Store({
state: { state: {
isCreatingValueStream: false, isCreatingValueStream: false,
formEvents,
}, },
actions: { actions: {
createValueStream: createValueStreamMock, createValueStream: createValueStreamMock,
updateValueStream: updateValueStreamMock, updateValueStream: updateValueStreamMock,
}, },
modules: {
customStages: {
namespaced: true,
state: {
formEvents,
},
},
},
}); });
const createComponent = ({ props = {}, data = {}, stubs = {} } = {}) => const createComponent = ({ props = {}, data = {}, stubs = {} } = {}) =>
......
...@@ -213,13 +213,6 @@ export const labelStopEvent = customStageLabelEvents.find( ...@@ -213,13 +213,6 @@ export const labelStopEvent = customStageLabelEvents.find(
(ev) => ev.identifier === labelStartEvent.allowedEndEvents[0], (ev) => ev.identifier === labelStartEvent.allowedEndEvents[0],
); );
export const rawCustomStageFormErrors = {
name: ['is reserved', 'cant be blank'],
start_event_identifier: ['cant be blank'],
};
export const customStageFormErrors = convertObjectPropsToCamelCase(rawCustomStageFormErrors);
const dateRange = getDatesInRange(startDate, endDate, toYmd); const dateRange = getDatesInRange(startDate, endDate, toYmd);
export const apiTasksByTypeData = getJSONFixture( export const apiTasksByTypeData = getJSONFixture(
......
...@@ -45,9 +45,6 @@ const mockGetters = { ...@@ -45,9 +45,6 @@ const mockGetters = {
currentValueStreamId: () => selectedValueStream.id, currentValueStreamId: () => selectedValueStream.id,
}; };
const stageEndpoint = ({ stageId }) =>
`/groups/${currentGroup.fullPath}/-/analytics/value_stream_analytics/value_streams/${selectedValueStream.id}/stages/${stageId}`;
jest.mock('~/flash'); jest.mock('~/flash');
describe('Value Stream Analytics actions', () => { describe('Value Stream Analytics actions', () => {
...@@ -422,248 +419,6 @@ describe('Value Stream Analytics actions', () => { ...@@ -422,248 +419,6 @@ describe('Value Stream Analytics actions', () => {
}); });
}); });
describe('updateStage', () => {
const stageId = 'cool-stage';
const payload = { hidden: true };
beforeEach(() => {
mock.onPut(stageEndpoint({ stageId }), payload).replyOnce(httpStatusCodes.OK, payload);
});
it('dispatches receiveUpdateStageSuccess and customStages/setSavingCustomStage', () => {
return testAction(
actions.updateStage,
{
id: stageId,
...payload,
},
state,
[],
[
{ type: 'requestUpdateStage' },
{ type: 'customStages/setSavingCustomStage' },
{
type: 'receiveUpdateStageSuccess',
payload,
},
],
);
});
describe('with a failed request', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onPut(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.NOT_FOUND);
});
it('dispatches receiveUpdateStageError', () => {
const data = {
id: stageId,
name: 'issue',
...payload,
};
return testAction(
actions.updateStage,
data,
state,
[],
[
{ type: 'requestUpdateStage' },
{ type: 'customStages/setSavingCustomStage' },
{
type: 'receiveUpdateStageError',
payload: {
status: httpStatusCodes.NOT_FOUND,
data,
},
},
],
);
});
it('flashes an error if the stage name already exists', () => {
return actions
.receiveUpdateStageError(
{
commit: () => {},
dispatch: () => Promise.resolve(),
state,
},
{
status: httpStatusCodes.UNPROCESSABLE_ENTITY,
responseData: {
errors: { name: ['is reserved'] },
},
data: {
name: stageId,
},
},
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: `'${stageId}' stage already exists`,
});
});
});
it('flashes an error message', () => {
return actions
.receiveUpdateStageError(
{
dispatch: () => Promise.resolve(),
commit: () => {},
state,
},
{ status: httpStatusCodes.BAD_REQUEST },
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was a problem saving your custom stage, please try again',
});
});
});
});
describe('receiveUpdateStageSuccess', () => {
const response = {
title: 'NEW - COOL',
};
it('will dispatch fetchGroupStagesAndEvents', () =>
testAction(
actions.receiveUpdateStageSuccess,
response,
state,
[{ type: types.RECEIVE_UPDATE_STAGE_SUCCESS }],
[
{ type: 'fetchGroupStagesAndEvents' },
{ type: 'customStages/showEditForm', payload: response },
],
));
it('will flash a success message', () => {
return actions
.receiveUpdateStageSuccess(
{
dispatch: () => {},
commit: () => {},
},
response,
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'Stage data updated',
type: 'notice',
});
});
});
describe('with an error', () => {
it('will flash an error message', () =>
actions
.receiveUpdateStageSuccess(
{
dispatch: () => Promise.reject(),
commit: () => {},
},
response,
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was a problem refreshing the data, please try again',
});
}));
});
});
});
describe('removeStage', () => {
const stageId = 'cool-stage';
beforeEach(() => {
mock.onDelete(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.OK);
});
it('dispatches receiveRemoveStageSuccess with put request response data', () => {
return testAction(
actions.removeStage,
stageId,
state,
[],
[
{ type: 'requestRemoveStage' },
{
type: 'receiveRemoveStageSuccess',
},
],
);
});
describe('with a failed request', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onDelete(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.NOT_FOUND);
});
it('dispatches receiveRemoveStageError', () => {
return testAction(
actions.removeStage,
stageId,
state,
[],
[
{ type: 'requestRemoveStage' },
{
type: 'receiveRemoveStageError',
payload: error,
},
],
);
});
it('flashes an error message', () => {
actions.receiveRemoveStageError({ commit: () => {}, state }, {});
expect(createFlash).toHaveBeenCalledWith({
message: 'There was an error removing your custom stage, please try again',
});
});
});
});
describe('receiveRemoveStageSuccess', () => {
const stageId = 'cool-stage';
beforeEach(() => {
mock.onDelete(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.OK);
state = { currentGroup };
});
it('dispatches fetchCycleAnalyticsData', () => {
return testAction(
actions.receiveRemoveStageSuccess,
stageId,
state,
[{ type: 'RECEIVE_REMOVE_STAGE_RESPONSE' }],
[{ type: 'fetchCycleAnalyticsData' }],
);
});
it('flashes a success message', () => {
return actions
.receiveRemoveStageSuccess(
{
dispatch: () => Promise.resolve(),
commit: () => {},
state,
},
{},
)
.then(() =>
expect(createFlash).toHaveBeenCalledWith({ message: 'Stage removed', type: 'notice' }),
);
});
});
describe('fetchStageMedianValues', () => { describe('fetchStageMedianValues', () => {
let mockDispatch = jest.fn(); let mockDispatch = jest.fn();
const fetchMedianResponse = activeStages.map(({ slug: id }) => ({ events: [], id })); const fetchMedianResponse = activeStages.map(({ slug: id }) => ({ events: [], id }));
...@@ -900,80 +655,6 @@ describe('Value Stream Analytics actions', () => { ...@@ -900,80 +655,6 @@ describe('Value Stream Analytics actions', () => {
)); ));
}); });
describe('reorderStage', () => {
const stageId = 'cool-stage';
const payload = { id: stageId, move_after_id: '2', move_before_id: '8' };
describe('with no errors', () => {
beforeEach(() => {
mock.onPut(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.OK);
});
it(`dispatches the ${types.REQUEST_REORDER_STAGE} and ${types.RECEIVE_REORDER_STAGE_SUCCESS} actions`, () => {
return testAction(
actions.reorderStage,
payload,
state,
[],
[{ type: 'requestReorderStage' }, { type: 'receiveReorderStageSuccess' }],
);
});
});
describe('with errors', () => {
beforeEach(() => {
mock.onPut(stageEndpoint({ stageId })).replyOnce(httpStatusCodes.NOT_FOUND);
});
it(`dispatches the ${types.REQUEST_REORDER_STAGE} and ${types.RECEIVE_REORDER_STAGE_ERROR} actions `, () => {
return testAction(
actions.reorderStage,
payload,
state,
[],
[
{ type: 'requestReorderStage' },
{ type: 'receiveReorderStageError', payload: { status: httpStatusCodes.NOT_FOUND } },
],
);
});
});
});
describe('receiveReorderStageError', () => {
beforeEach(() => {});
it(`commits the ${types.RECEIVE_REORDER_STAGE_ERROR} mutation and flashes an error`, () => {
return testAction(
actions.receiveReorderStageError,
null,
state,
[
{
type: types.RECEIVE_REORDER_STAGE_ERROR,
},
],
[],
).then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was an error updating the stage order. Please try reloading the page.',
});
});
});
});
describe('receiveReorderStageSuccess', () => {
it(`commits the ${types.RECEIVE_REORDER_STAGE_SUCCESS} mutation`, () => {
return testAction(
actions.receiveReorderStageSuccess,
null,
state,
[{ type: types.RECEIVE_REORDER_STAGE_SUCCESS }],
[],
);
});
});
describe('createValueStream', () => { describe('createValueStream', () => {
const payload = { const payload = {
name: 'cool value stream', name: 'cool value stream',
......
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as actions from 'ee/analytics/cycle_analytics/store/modules/custom_stages/actions';
import * as types from 'ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types';
import testAction from 'helpers/vuex_action_helper';
import createFlash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status';
import { currentGroup, endpoints, rawCustomStage } from '../../../mock_data';
jest.mock('~/flash');
describe('Custom stage actions', () => {
let state;
let mock;
const selectedStage = rawCustomStage;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
state = { currentGroup: null };
});
describe('createStage', () => {
describe('with valid data', () => {
const customStageData = {
startEventIdentifier: 'start_event',
endEventIdentifier: 'end_event',
name: 'cool-new-stage',
};
beforeEach(() => {
state = { ...state, currentGroup };
mock.onPost(endpoints.baseStagesEndpointstageData).reply(201, customStageData);
});
it(`dispatches the 'receiveCreateStageSuccess' action`, () =>
testAction(
actions.createStage,
customStageData,
state,
[],
[
{ type: 'clearFormErrors' },
{ type: 'setSavingCustomStage' },
{
type: 'receiveCreateStageSuccess',
payload: { data: customStageData, status: 201 },
},
],
));
});
describe('with errors', () => {
const message = 'failed';
const errors = {
endEventIdentifier: ['Cant be blank'],
};
const customStageData = {
startEventIdentifier: 'start_event',
endEventIdentifier: '',
name: 'cool-new-stage',
};
beforeEach(() => {
state = { ...state, currentGroup };
mock
.onPost(endpoints.baseStagesEndpointstageData)
.reply(httpStatusCodes.UNPROCESSABLE_ENTITY, {
message,
errors,
});
});
it(`dispatches the 'receiveCreateStageError' action`, () =>
testAction(
actions.createStage,
customStageData,
state,
[],
[
{ type: 'clearFormErrors' },
{ type: 'setSavingCustomStage' },
{
type: 'receiveCreateStageError',
payload: {
data: customStageData,
errors,
message,
status: httpStatusCodes.UNPROCESSABLE_ENTITY,
},
},
],
));
});
});
describe('receiveCreateStageError', () => {
const response = {
data: { name: 'uh oh' },
};
beforeEach(() => {});
it('will commit the RECEIVE_CREATE_STAGE_ERROR mutation', () =>
testAction(
actions.receiveCreateStageError,
response,
state,
[{ type: types.RECEIVE_CREATE_STAGE_ERROR }],
[{ type: 'setStageFormErrors', payload: {} }],
));
it('will flash an error message', () => {
return actions
.receiveCreateStageError(
{
dispatch: () => Promise.resolve(),
commit: () => {},
},
response,
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was a problem saving your custom stage, please try again',
});
});
});
describe('with a stage name error', () => {
it('will flash an error message', () => {
return actions
.receiveCreateStageError(
{
dispatch: () => Promise.resolve(),
commit: () => {},
},
{
...response,
status: httpStatusCodes.UNPROCESSABLE_ENTITY,
errors: { name: ['is reserved'] },
},
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({ message: "'uh oh' stage already exists" });
});
});
});
});
describe('receiveCreateStageSuccess', () => {
const response = {
data: {
title: 'COOL',
},
};
it('will dispatch fetchGroupStagesAndEvents', () =>
testAction(
actions.receiveCreateStageSuccess,
response,
state,
[{ type: types.RECEIVE_CREATE_STAGE_SUCCESS }],
[{ type: 'fetchGroupStagesAndEvents', payload: null }, { type: 'clearSavingCustomStage' }],
));
describe('with an error', () => {
it('will flash an error message', () =>
actions
.receiveCreateStageSuccess(
{
dispatch: () => Promise.reject(),
commit: () => {},
},
response,
)
.then(() => {
expect(createFlash).toHaveBeenCalledWith({
message: 'There was a problem refreshing the data, please try again',
});
}));
});
});
describe('setStageFormErrors', () => {
it('commits the "SET_STAGE_FORM_ERRORS" mutation', () => {
return testAction(
actions.setStageFormErrors,
[],
state,
[{ type: types.SET_STAGE_FORM_ERRORS, payload: [] }],
[],
);
});
});
describe('clearFormErrors', () => {
it('commits the "CLEAR_FORM_ERRORS" mutation', () => {
return testAction(
actions.clearFormErrors,
[],
state,
[{ type: types.CLEAR_FORM_ERRORS }],
[],
);
});
});
describe('setStageEvents', () => {
it('commits the "SET_STAGE_EVENTS" mutation', () => {
return testAction(
actions.setStageEvents,
[],
state,
[{ type: types.SET_STAGE_EVENTS, payload: [] }],
[],
);
});
});
describe('hideForm', () => {
it('commits the "HIDE_FORM" mutation', () => {
return testAction(actions.hideForm, null, state, [{ type: types.HIDE_FORM }], []);
});
});
describe('showCreateForm', () => {
it('commits the "SHOW_CREATE_FORM" mutation', () => {
return testAction(
actions.showCreateForm,
null,
state,
[
{ type: types.SET_LOADING },
{ type: types.SET_FORM_INITIAL_DATA },
{ type: types.SHOW_CREATE_FORM },
],
[],
);
});
});
describe('showEditForm', () => {
it('commits the "SHOW_EDIT_FORM" mutation with initial data', () => {
return testAction(
actions.showEditForm,
selectedStage,
state,
[
{ type: types.SET_LOADING },
{ type: types.SET_FORM_INITIAL_DATA, payload: rawCustomStage },
{ type: types.SHOW_EDIT_FORM },
],
[{ type: 'setSelectedStage', payload: rawCustomStage }, { type: 'clearSavingCustomStage' }],
);
});
});
});
import * as getters from 'ee/analytics/cycle_analytics/store/modules/custom_stages/getters';
describe('Custom stages getters', () => {
describe.each`
state | result
${{ isCreatingCustomStage: true, isEditingCustomStage: true }} | ${true}
${{ isCreatingCustomStage: false, isEditingCustomStage: true }} | ${true}
${{ isCreatingCustomStage: true, isEditingCustomStage: false }} | ${true}
${{ isCreatingCustomStage: false, isEditingCustomStage: false }} | ${false}
`('customStageFormActive', ({ state, result }) => {
it(`with state ${state} returns ${result}`, () => {
expect(getters.customStageFormActive(state)).toEqual(result);
});
});
});
import * as types from 'ee/analytics/cycle_analytics/store/modules/custom_stages/mutation_types';
import mutations from 'ee/analytics/cycle_analytics/store/modules/custom_stages/mutations';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { rawCustomStageEvents, camelCasedStageEvents, rawCustomStage } from '../../../mock_data';
let state = null;
describe('Custom stage mutations', () => {
beforeEach(() => {
state = {};
});
afterEach(() => {
state = null;
});
it.each`
mutation | stateKey | value
${types.HIDE_FORM} | ${'isCreatingCustomStage'} | ${false}
${types.HIDE_FORM} | ${'isEditingCustomStage'} | ${false}
${types.HIDE_FORM} | ${'formErrors'} | ${null}
${types.HIDE_FORM} | ${'formInitialData'} | ${null}
${types.CLEAR_FORM_ERRORS} | ${'formErrors'} | ${null}
${types.SHOW_CREATE_FORM} | ${'isCreatingCustomStage'} | ${true}
${types.SHOW_CREATE_FORM} | ${'isEditingCustomStage'} | ${false}
${types.SHOW_CREATE_FORM} | ${'formErrors'} | ${null}
${types.SHOW_CREATE_FORM} | ${'formInitialData'} | ${null}
${types.SHOW_EDIT_FORM} | ${'isEditingCustomStage'} | ${true}
${types.SHOW_EDIT_FORM} | ${'isCreatingCustomStage'} | ${false}
${types.SHOW_EDIT_FORM} | ${'formErrors'} | ${null}
${types.RECEIVE_CREATE_STAGE_SUCCESS} | ${'formErrors'} | ${null}
${types.RECEIVE_CREATE_STAGE_SUCCESS} | ${'formInitialData'} | ${null}
${types.RECEIVE_CREATE_STAGE_ERROR} | ${'isSavingCustomStage'} | ${false}
${types.SET_SAVING_CUSTOM_STAGE} | ${'isSavingCustomStage'} | ${true}
${types.CLEAR_SAVING_CUSTOM_STAGE} | ${'isSavingCustomStage'} | ${false}
${types.SET_LOADING} | ${'isLoadingCustomStage'} | ${true}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state);
expect(state[stateKey]).toEqual(value);
});
describe(`${types.SET_STAGE_EVENTS}`, () => {
it('will set formEvents', () => {
state = {};
mutations[types.SET_STAGE_EVENTS](state, rawCustomStageEvents);
expect(state.formEvents).toEqual(camelCasedStageEvents);
});
});
describe(`${types.SET_STAGE_FORM_ERRORS}`, () => {
const mockFormError = { start_identifier: ['Cant be blank'] };
it('will set formErrors', () => {
state = {};
mutations[types.SET_STAGE_FORM_ERRORS](state, mockFormError);
expect(state.formErrors).toEqual(convertObjectPropsToCamelCase(mockFormError));
});
});
describe(`${types.SET_FORM_INITIAL_DATA}`, () => {
const mockStage = {
endEventIdentifier: 'issue_first_added_to_board',
endEventLabelId: null,
id: 18,
name: 'Coolest beans stage',
startEventIdentifier: 'issue_first_mentioned_in_commit',
startEventLabelId: null,
};
it('will set formInitialData', () => {
state = {};
mutations[types.SET_FORM_INITIAL_DATA](state, rawCustomStage);
expect(state.formInitialData).toEqual(mockStage);
});
});
});
...@@ -16,6 +16,8 @@ import { ...@@ -16,6 +16,8 @@ import {
selectedProjects, selectedProjects,
customizableStagesAndEvents, customizableStagesAndEvents,
valueStreams, valueStreams,
rawCustomStageEvents,
camelCasedStageEvents,
} from '../mock_data'; } from '../mock_data';
let state = null; let state = null;
...@@ -41,11 +43,6 @@ describe('Value Stream Analytics mutations', () => { ...@@ -41,11 +43,6 @@ describe('Value Stream Analytics mutations', () => {
${types.REQUEST_VALUE_STREAM_DATA} | ${'isLoading'} | ${true} ${types.REQUEST_VALUE_STREAM_DATA} | ${'isLoading'} | ${true}
${types.RECEIVE_GROUP_STAGES_ERROR} | ${'stages'} | ${[]} ${types.RECEIVE_GROUP_STAGES_ERROR} | ${'stages'} | ${[]}
${types.REQUEST_GROUP_STAGES} | ${'stages'} | ${[]} ${types.REQUEST_GROUP_STAGES} | ${'stages'} | ${[]}
${types.REQUEST_UPDATE_STAGE} | ${'isLoading'} | ${true}
${types.RECEIVE_UPDATE_STAGE_SUCCESS} | ${'isLoading'} | ${false}
${types.RECEIVE_UPDATE_STAGE_ERROR} | ${'isLoading'} | ${false}
${types.REQUEST_REMOVE_STAGE} | ${'isLoading'} | ${true}
${types.RECEIVE_REMOVE_STAGE_RESPONSE} | ${'isLoading'} | ${false}
${types.REQUEST_STAGE_MEDIANS} | ${'medians'} | ${{}} ${types.REQUEST_STAGE_MEDIANS} | ${'medians'} | ${{}}
${types.RECEIVE_STAGE_MEDIANS_ERROR} | ${'medians'} | ${{}} ${types.RECEIVE_STAGE_MEDIANS_ERROR} | ${'medians'} | ${{}}
${types.REQUEST_CREATE_VALUE_STREAM} | ${'isCreatingValueStream'} | ${true} ${types.REQUEST_CREATE_VALUE_STREAM} | ${'isCreatingValueStream'} | ${true}
...@@ -64,6 +61,7 @@ describe('Value Stream Analytics mutations', () => { ...@@ -64,6 +61,7 @@ describe('Value Stream Analytics mutations', () => {
${types.INITIALIZE_VALUE_STREAM_SUCCESS} | ${'isLoading'} | ${false} ${types.INITIALIZE_VALUE_STREAM_SUCCESS} | ${'isLoading'} | ${false}
${types.REQUEST_STAGE_COUNTS} | ${'stageCounts'} | ${{}} ${types.REQUEST_STAGE_COUNTS} | ${'stageCounts'} | ${{}}
${types.RECEIVE_STAGE_COUNTS_ERROR} | ${'stageCounts'} | ${{}} ${types.RECEIVE_STAGE_COUNTS_ERROR} | ${'stageCounts'} | ${{}}
${types.SET_STAGE_EVENTS} | ${'formEvents'} | ${[]}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => { `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state); mutations[mutation](state);
...@@ -100,6 +98,7 @@ describe('Value Stream Analytics mutations', () => { ...@@ -100,6 +98,7 @@ describe('Value Stream Analytics mutations', () => {
${types.RECEIVE_UPDATE_VALUE_STREAM_SUCCESS} | ${valueStreams[1]} | ${{ selectedValueStream: valueStreams[1] }} ${types.RECEIVE_UPDATE_VALUE_STREAM_SUCCESS} | ${valueStreams[1]} | ${{ selectedValueStream: valueStreams[1] }}
${types.SET_PAGINATION} | ${pagination} | ${{ pagination: { ...pagination, sort: PAGINATION_SORT_FIELD_END_EVENT, direction: PAGINATION_SORT_DIRECTION_DESC } }} ${types.SET_PAGINATION} | ${pagination} | ${{ pagination: { ...pagination, sort: PAGINATION_SORT_FIELD_END_EVENT, direction: PAGINATION_SORT_DIRECTION_DESC } }}
${types.SET_PAGINATION} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} | ${{ pagination: { ...pagination, sort: 'duration', direction: 'asc' } }} ${types.SET_PAGINATION} | ${{ ...pagination, sort: 'duration', direction: 'asc' }} | ${{ pagination: { ...pagination, sort: 'duration', direction: 'asc' } }}
${types.SET_STAGE_EVENTS} | ${rawCustomStageEvents} | ${{ formEvents: camelCasedStageEvents }}
`( `(
'$mutation with payload $payload will update state with $expectedState', '$mutation with payload $payload will update state with $expectedState',
({ mutation, payload, expectedState }) => { ({ mutation, payload, expectedState }) => {
......
...@@ -478,75 +478,6 @@ describe('Api', () => { ...@@ -478,75 +478,6 @@ describe('Api', () => {
}); });
}); });
describe('cycleAnalyticsCreateStage', () => {
it('submit the custom stage data', (done) => {
const response = {};
const customStage = {
name: 'cool-stage',
start_event_identifier: 'issue_created',
start_event_label_id: null,
end_event_identifier: 'issue_closed',
end_event_label_id: null,
};
const expectedUrl = valueStreamBaseUrl({
id: valueStreamId,
resource: 'stages',
});
mock.onPost(expectedUrl).reply(httpStatus.OK, response);
Api.cycleAnalyticsCreateStage({ groupId, valueStreamId, data: customStage })
.then(({ data, config: { data: reqData, url } }) => {
expect(data).toEqual(response);
expect(JSON.parse(reqData)).toMatchObject(customStage);
expect(url).toEqual(expectedUrl);
})
.then(done)
.catch(done.fail);
});
});
describe('cycleAnalyticsUpdateStage', () => {
it('updates the stage data', (done) => {
const response = { id: stageId, custom: false, hidden: true, name: 'nice-stage' };
const stageData = { name: 'nice-stage', hidden: true };
const expectedUrl = valueStreamBaseUrl({
id: valueStreamId,
resource: `stages/${stageId}`,
});
mock.onPut(expectedUrl).reply(httpStatus.OK, response);
Api.cycleAnalyticsUpdateStage({ groupId, valueStreamId, stageId, data: stageData })
.then(({ data, config: { data: reqData, url } }) => {
expect(data).toEqual(response);
expect(JSON.parse(reqData)).toMatchObject(stageData);
expect(url).toEqual(expectedUrl);
})
.then(done)
.catch(done.fail);
});
});
describe('cycleAnalyticsRemoveStage', () => {
it('deletes the specified data', (done) => {
const response = { id: stageId, hidden: true, custom: true };
const expectedUrl = valueStreamBaseUrl({
id: valueStreamId,
resource: `stages/${stageId}`,
});
mock.onDelete(expectedUrl).reply(httpStatus.OK, response);
Api.cycleAnalyticsRemoveStage({ groupId, valueStreamId, stageId })
.then(({ data, config: { url } }) => {
expect(data).toEqual(response);
expect(url).toEqual(expectedUrl);
})
.then(done)
.catch(done.fail);
});
});
describe('cycleAnalyticsDurationChart', () => { describe('cycleAnalyticsDurationChart', () => {
it('fetches stage duration data', (done) => { it('fetches stage duration data', (done) => {
const response = []; const response = [];
......
...@@ -1044,9 +1044,6 @@ msgstr "" ...@@ -1044,9 +1044,6 @@ msgstr ""
msgid "'%{name}' Value Stream saved" msgid "'%{name}' Value Stream saved"
msgstr "" msgstr ""
msgid "'%{name}' stage already exists"
msgstr ""
msgid "'%{source}' is not a import source" msgid "'%{source}' is not a import source"
msgstr "" msgstr ""
...@@ -30745,12 +30742,6 @@ msgstr "" ...@@ -30745,12 +30742,6 @@ msgstr ""
msgid "Stage" msgid "Stage"
msgstr "" msgstr ""
msgid "Stage data updated"
msgstr ""
msgid "Stage removed"
msgstr ""
msgid "StageName|Build" msgid "StageName|Build"
msgstr "" msgstr ""
...@@ -32752,12 +32743,6 @@ msgstr "" ...@@ -32752,12 +32743,6 @@ msgstr ""
msgid "There was a problem fetching users." msgid "There was a problem fetching users."
msgstr "" msgstr ""
msgid "There was a problem refreshing the data, please try again"
msgstr ""
msgid "There was a problem saving your custom stage, please try again"
msgstr ""
msgid "There was a problem sending the confirmation email" msgid "There was a problem sending the confirmation email"
msgstr "" msgstr ""
...@@ -32851,9 +32836,6 @@ msgstr "" ...@@ -32851,9 +32836,6 @@ msgstr ""
msgid "There was an error removing the e-mail." msgid "There was an error removing the e-mail."
msgstr "" msgstr ""
msgid "There was an error removing your custom stage, please try again"
msgstr ""
msgid "There was an error resetting group pipeline minutes." msgid "There was an error resetting group pipeline minutes."
msgstr "" msgstr ""
...@@ -32896,9 +32878,6 @@ msgstr "" ...@@ -32896,9 +32878,6 @@ msgstr ""
msgid "There was an error updating the dashboard, branch named: %{branch} already exists." msgid "There was an error updating the dashboard, branch named: %{branch} already exists."
msgstr "" msgstr ""
msgid "There was an error updating the stage order. Please try reloading the page."
msgstr ""
msgid "There was an error when reseting email token." msgid "There was an error when reseting email token."
msgstr "" msgstr ""
...@@ -37648,9 +37627,6 @@ msgstr "" ...@@ -37648,9 +37627,6 @@ msgstr ""
msgid "Your comment will be discarded." msgid "Your comment will be discarded."
msgstr "" msgstr ""
msgid "Your custom stage '%{title}' was created"
msgstr ""
msgid "Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}." msgid "Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}."
msgstr "" msgstr ""
......
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