Commit 13b0dbf7 authored by Martin Wortschack's avatar Martin Wortschack

Merge branch '197337-move-tasks-by-type-vuex-into-module' into 'master'

Move type of work vuex code into module

Closes #214892

See merge request gitlab-org/gitlab!29674
parents 962ae39d b5afaac5
...@@ -52,8 +52,6 @@ export default { ...@@ -52,8 +52,6 @@ export default {
'featureFlags', 'featureFlags',
'isLoading', 'isLoading',
'isLoadingStage', 'isLoadingStage',
'isLoadingTasksByTypeChart',
'isLoadingTasksByTypeChartTopLabels',
'isEmptyStage', 'isEmptyStage',
'isSavingCustomStage', 'isSavingCustomStage',
'isCreatingCustomStage', 'isCreatingCustomStage',
...@@ -63,25 +61,30 @@ export default { ...@@ -63,25 +61,30 @@ export default {
'selectedStage', 'selectedStage',
'stages', 'stages',
'summary', 'summary',
'topRankedLabels',
'currentStageEvents', 'currentStageEvents',
'customStageFormEvents', 'customStageFormEvents',
'errorCode', 'errorCode',
'startDate', 'startDate',
'endDate', 'endDate',
'tasksByType',
'medians', 'medians',
'customStageFormErrors', 'customStageFormErrors',
]), ]),
...mapState('typeOfWork', [
'isLoadingTasksByTypeChart',
'isLoadingTasksByTypeChartTopLabels',
'topRankedLabels',
'subject',
'selectedLabelIds',
]),
...mapGetters([ ...mapGetters([
'hasNoAccessError', 'hasNoAccessError',
'currentGroupPath', 'currentGroupPath',
'tasksByTypeChartData',
'activeStages', 'activeStages',
'selectedProjectIds', 'selectedProjectIds',
'enableCustomOrdering', 'enableCustomOrdering',
'cycleAnalyticsRequestParams', 'cycleAnalyticsRequestParams',
]), ]),
...mapGetters('typeOfWork', ['tasksByTypeChartData']),
shouldRenderEmptyState() { shouldRenderEmptyState() {
return !this.selectedGroup; return !this.selectedGroup;
}, },
...@@ -95,12 +98,10 @@ export default { ...@@ -95,12 +98,10 @@ export default {
return this.featureFlags.hasDurationChart && !this.hasNoAccessError && !this.isLoading; return this.featureFlags.hasDurationChart && !this.hasNoAccessError && !this.isLoading;
}, },
shouldDisplayTypeOfWorkCharts() { shouldDisplayTypeOfWorkCharts() {
return this.featureFlags.hasTasksByTypeChart && !this.hasNoAccessError; return this.featureFlags.hasTasksByTypeChart && !this.hasNoAccessError && !this.isLoading;
}, },
isLoadingTypeOfWork() { isLoadingTypeOfWork() {
return ( return this.isLoadingTasksByTypeChartTopLabels || this.isLoadingTasksByTypeChart;
this.isLoading || this.isLoadingTasksByTypeChartTopLabels || this.isLoadingTasksByTypeChart
);
}, },
hasDateRangeSet() { hasDateRangeSet() {
return this.startDate && this.endDate; return this.startDate && this.endDate;
...@@ -111,7 +112,8 @@ export default { ...@@ -111,7 +112,8 @@ export default {
startDate, startDate,
endDate, endDate,
selectedProjectIds, selectedProjectIds,
tasksByType: { subject, selectedLabelIds }, subject,
selectedLabelIds,
} = this; } = this;
return { return {
selectedGroup, selectedGroup,
...@@ -152,16 +154,15 @@ export default { ...@@ -152,16 +154,15 @@ export default {
'showCustomStageForm', 'showCustomStageForm',
'showEditCustomStageForm', 'showEditCustomStageForm',
'setDateRange', 'setDateRange',
'fetchTasksByTypeData',
'createCustomStage', 'createCustomStage',
'updateStage', 'updateStage',
'removeStage', 'removeStage',
'setFeatureFlags', 'setFeatureFlags',
'clearCustomStageFormErrors', 'clearCustomStageFormErrors',
'updateStage', 'updateStage',
'setTasksByTypeFilters',
'reorderStage', 'reorderStage',
]), ]),
...mapActions('typeOfWork', ['setTasksByTypeFilters']),
onGroupSelect(group) { onGroupSelect(group) {
this.setSelectedGroup(group); this.setSelectedGroup(group);
this.fetchCycleAnalyticsData(); this.fetchCycleAnalyticsData();
......
...@@ -3,14 +3,7 @@ import createFlash from '~/flash'; ...@@ -3,14 +3,7 @@ import createFlash from '~/flash';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { removeFlash } from '../utils'; import { removeFlash, handleErrorOrRethrow } from '../utils';
const handleErrorOrRethrow = ({ action, error }) => {
if (error?.response?.status === httpStatus.FORBIDDEN) {
throw error;
}
action();
};
const isStageNameExistsError = ({ status, errors }) => { const isStageNameExistsError = ({ status, errors }) => {
const ERROR_NAME_RESERVED = 'is reserved'; const ERROR_NAME_RESERVED = 'is reserved';
...@@ -105,13 +98,9 @@ export const fetchStageMedianValues = ({ state, dispatch, getters }) => { ...@@ -105,13 +98,9 @@ export const fetchStageMedianValues = ({ state, dispatch, getters }) => {
}; };
export const requestCycleAnalyticsData = ({ commit }) => commit(types.REQUEST_CYCLE_ANALYTICS_DATA); export const requestCycleAnalyticsData = ({ commit }) => commit(types.REQUEST_CYCLE_ANALYTICS_DATA);
export const receiveCycleAnalyticsDataSuccess = ({ state, commit, dispatch }) => { export const receiveCycleAnalyticsDataSuccess = ({ commit, dispatch }) => {
commit(types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS); commit(types.RECEIVE_CYCLE_ANALYTICS_DATA_SUCCESS);
dispatch('typeOfWork/fetchTopRankedGroupLabels');
const { featureFlags: { hasTasksByTypeChart = false } = {} } = state;
const promises = [];
if (hasTasksByTypeChart) promises.push('fetchTopRankedGroupLabels');
return Promise.all(promises.map(func => dispatch(func)));
}; };
export const receiveCycleAnalyticsDataError = ({ commit }, { response }) => { export const receiveCycleAnalyticsDataError = ({ commit }, { response }) => {
...@@ -168,44 +157,6 @@ export const showEditCustomStageForm = ({ commit, dispatch }, selectedStage = {} ...@@ -168,44 +157,6 @@ export const showEditCustomStageForm = ({ commit, dispatch }, selectedStage = {}
export const requestGroupStagesAndEvents = ({ commit }) => export const requestGroupStagesAndEvents = ({ commit }) =>
commit(types.REQUEST_GROUP_STAGES_AND_EVENTS); commit(types.REQUEST_GROUP_STAGES_AND_EVENTS);
export const receiveTopRankedGroupLabelsSuccess = ({ commit, dispatch }, data) => {
commit(types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS, data);
dispatch('fetchTasksByTypeData');
};
export const receiveTopRankedGroupLabelsError = ({ commit }, error) => {
commit(types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR, error);
createFlash(__('There was an error fetching the top labels for the selected group'));
};
export const requestTopRankedGroupLabels = ({ commit }) =>
commit(types.REQUEST_TOP_RANKED_GROUP_LABELS);
export const fetchTopRankedGroupLabels = ({
dispatch,
state,
getters: {
currentGroupPath,
cycleAnalyticsRequestParams: { created_after, created_before },
},
}) => {
dispatch('requestTopRankedGroupLabels');
const { subject } = state.tasksByType;
return Api.cycleAnalyticsTopLabels(currentGroupPath, {
subject,
created_after,
created_before,
})
.then(({ data }) => dispatch('receiveTopRankedGroupLabelsSuccess', data))
.catch(error =>
handleErrorOrRethrow({
error,
action: () => dispatch('receiveTopRankedGroupLabelsError', error),
}),
);
};
export const receiveGroupStagesAndEventsError = ({ commit }, error) => { export const receiveGroupStagesAndEventsError = ({ commit }, error) => {
commit(types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR, error); commit(types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR, error);
createFlash(__('There was an error fetching value stream analytics stages.')); createFlash(__('There was an error fetching value stream analytics stages.'));
...@@ -295,41 +246,6 @@ export const createCustomStage = ({ dispatch, state }, data) => { ...@@ -295,41 +246,6 @@ export const createCustomStage = ({ dispatch, state }, data) => {
}); });
}; };
export const receiveTasksByTypeDataError = ({ commit }, error) => {
commit(types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR, error);
createFlash(__('There was an error fetching data for the tasks by type chart'));
};
export const fetchTasksByTypeData = ({ dispatch, commit, state, getters }) => {
const {
currentGroupPath,
cycleAnalyticsRequestParams: { created_after, created_before, project_ids },
} = getters;
const {
tasksByType: { subject, selectedLabelIds },
} = state;
// ensure we clear any chart data currently in state
commit(types.REQUEST_TASKS_BY_TYPE_DATA);
// dont request if we have no labels selected...for now
if (selectedLabelIds.length) {
const params = {
created_after,
created_before,
project_ids,
subject,
label_ids: selectedLabelIds,
};
return Api.cycleAnalyticsTasksByType(currentGroupPath, params)
.then(({ data }) => commit(types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS, data))
.catch(error => dispatch('receiveTasksByTypeDataError', error));
}
return commit(types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS, []);
};
export const requestUpdateStage = ({ commit }) => commit(types.REQUEST_UPDATE_STAGE); export const requestUpdateStage = ({ commit }) => commit(types.REQUEST_UPDATE_STAGE);
export const receiveUpdateStageSuccess = ({ commit, dispatch }, updatedData) => { export const receiveUpdateStageSuccess = ({ commit, dispatch }, updatedData) => {
commit(types.RECEIVE_UPDATE_STAGE_SUCCESS); commit(types.RECEIVE_UPDATE_STAGE_SUCCESS);
...@@ -396,11 +312,6 @@ export const removeStage = ({ dispatch, state }, stageId) => { ...@@ -396,11 +312,6 @@ export const removeStage = ({ dispatch, state }, stageId) => {
.catch(error => dispatch('receiveRemoveStageError', error)); .catch(error => dispatch('receiveRemoveStageError', error));
}; };
export const setTasksByTypeFilters = ({ dispatch, commit }, data) => {
commit(types.SET_TASKS_BY_TYPE_FILTERS, data);
dispatch('fetchTopRankedGroupLabels');
};
export const initializeCycleAnalyticsSuccess = ({ commit }) => export const initializeCycleAnalyticsSuccess = ({ commit }) =>
commit(types.INITIALIZE_CYCLE_ANALYTICS_SUCCESS); commit(types.INITIALIZE_CYCLE_ANALYTICS_SUCCESS);
......
...@@ -2,7 +2,6 @@ import dateFormat from 'dateformat'; ...@@ -2,7 +2,6 @@ import dateFormat from 'dateformat';
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { dateFormats } from '../../shared/constants'; import { dateFormats } from '../../shared/constants';
import { getTasksByTypeData } from '../utils';
export const hasNoAccessError = state => state.errorCode === httpStatus.FORBIDDEN; export const hasNoAccessError = state => state.errorCode === httpStatus.FORBIDDEN;
...@@ -18,17 +17,6 @@ export const cycleAnalyticsRequestParams = ({ startDate = null, endDate = null } ...@@ -18,17 +17,6 @@ export const cycleAnalyticsRequestParams = ({ startDate = null, endDate = null }
created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null, created_before: endDate ? dateFormat(endDate, dateFormats.isoDate) : null,
}); });
export const tasksByTypeChartData = ({ tasksByType, startDate, endDate }) => {
if (tasksByType && tasksByType.data.length) {
return getTasksByTypeData({
data: tasksByType.data,
startDate,
endDate,
});
}
return { groupBy: [], data: [], seriesNames: [] };
};
const filterStagesByHiddenStatus = (stages = [], isHidden = true) => const filterStagesByHiddenStatus = (stages = [], isHidden = true) =>
stages.filter(({ hidden = false }) => hidden === isHidden); stages.filter(({ hidden = false }) => hidden === isHidden);
......
...@@ -5,6 +5,7 @@ import * as getters from './getters'; ...@@ -5,6 +5,7 @@ import * as getters from './getters';
import mutations from './mutations'; import mutations from './mutations';
import state from './state'; import state from './state';
import durationChart from './modules/duration_chart/index'; import durationChart from './modules/duration_chart/index';
import typeOfWork from './modules/type_of_work/index';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -14,5 +15,5 @@ export default () => ...@@ -14,5 +15,5 @@ export default () =>
getters, getters,
mutations, mutations,
state, state,
modules: { durationChart }, modules: { durationChart, typeOfWork },
}); });
import Api from 'ee/api';
import createFlash from '~/flash';
import { __ } from '~/locale';
import * as types from './mutation_types';
import { handleErrorOrRethrow } from '../../../utils';
export const receiveTopRankedGroupLabelsSuccess = ({ commit, dispatch }, data) => {
commit(types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS, data);
dispatch('fetchTasksByTypeData');
};
export const receiveTopRankedGroupLabelsError = ({ commit }, error) => {
commit(types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR, error);
createFlash(__('There was an error fetching the top labels for the selected group'));
};
export const fetchTopRankedGroupLabels = ({ dispatch, commit, state, rootGetters }) => {
commit(types.REQUEST_TOP_RANKED_GROUP_LABELS);
const {
currentGroupPath,
cycleAnalyticsRequestParams: { created_after, created_before },
} = rootGetters;
const { subject } = state;
return Api.cycleAnalyticsTopLabels(currentGroupPath, {
subject,
created_after,
created_before,
})
.then(({ data }) => dispatch('receiveTopRankedGroupLabelsSuccess', data))
.catch(error =>
handleErrorOrRethrow({
error,
action: () => dispatch('receiveTopRankedGroupLabelsError', error),
}),
);
};
export const receiveTasksByTypeDataError = ({ commit }, error) => {
commit(types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR, error);
createFlash(__('There was an error fetching data for the tasks by type chart'));
};
export const fetchTasksByTypeData = ({ dispatch, commit, state, rootGetters }) => {
const {
currentGroupPath,
cycleAnalyticsRequestParams: { created_after, created_before, project_ids },
} = rootGetters;
const { subject, selectedLabelIds } = state;
// ensure we clear any chart data currently in state
commit(types.REQUEST_TASKS_BY_TYPE_DATA);
// dont request if we have no labels selected...for now
if (selectedLabelIds.length) {
const params = {
created_after,
created_before,
project_ids,
subject,
label_ids: selectedLabelIds,
};
return Api.cycleAnalyticsTasksByType(currentGroupPath, params)
.then(({ data }) => commit(types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS, data))
.catch(error => dispatch('receiveTasksByTypeDataError', error));
}
return commit(types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS, []);
};
export const setTasksByTypeFilters = ({ dispatch, commit }, data) => {
commit(types.SET_TASKS_BY_TYPE_FILTERS, data);
dispatch('fetchTasksByTypeData');
};
import { getTasksByTypeData } from '../../../utils';
export const tasksByTypeChartData = ({ data = [] } = {}, _, rootState = {}) => {
const { startDate = null, endDate = null } = rootState;
return data.length
? getTasksByTypeData({
data,
startDate,
endDate,
})
: { groupBy: [], data: [], seriesNames: [] };
};
export default () => ({ tasksByTypeChartData });
import * as actions from './actions';
import * as getters from './getters';
import mutations from './mutations';
import state from './state';
export default {
namespaced: true,
actions,
getters,
mutations,
state,
};
export const REQUEST_TOP_RANKED_GROUP_LABELS = 'REQUEST_TOP_RANKED_GROUP_LABELS';
export const RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS = 'RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS';
export const RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR = 'RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR';
export const REQUEST_TASKS_BY_TYPE_DATA = 'REQUEST_TASKS_BY_TYPE_DATA';
export const RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS = 'RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS';
export const RECEIVE_TASKS_BY_TYPE_DATA_ERROR = 'RECEIVE_TASKS_BY_TYPE_DATA_ERROR';
export const SET_TASKS_BY_TYPE_SUBJECT = 'SET_TASKS_BY_TYPE_SUBJECT';
export const SET_TASKS_BY_TYPE_LABELS = 'SET_TASKS_BY_TYPE_LABELS';
export const SET_TASKS_BY_TYPE_FILTERS = 'SET_TASKS_BY_TYPE_FILTERS';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import * as types from './mutation_types';
import { transformRawTasksByTypeData, toggleSelectedLabel } from '../../../utils';
import { TASKS_BY_TYPE_FILTERS } from '../../../constants';
export default {
[types.REQUEST_TOP_RANKED_GROUP_LABELS](state) {
state.isLoadingTasksByTypeChartTopLabels = true;
state.topRankedLabels = [];
state.selectedLabelIds = [];
},
[types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS](state, data = []) {
state.isLoadingTasksByTypeChartTopLabels = false;
state.topRankedLabels = data.map(convertObjectPropsToCamelCase);
state.selectedLabelIds = data.map(({ id }) => id);
},
[types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR](state) {
state.isLoadingTasksByTypeChartTopLabels = false;
state.topRankedLabels = [];
state.selectedLabelIds = [];
},
[types.REQUEST_TASKS_BY_TYPE_DATA](state) {
state.isLoadingTasksByTypeChart = true;
},
[types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR](state) {
state.isLoadingTasksByTypeChart = false;
},
[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, data = []) {
state.isLoadingTasksByTypeChart = false;
state.data = transformRawTasksByTypeData(data);
},
[types.SET_TASKS_BY_TYPE_FILTERS](state, { filter, value }) {
const { selectedLabelIds } = state;
switch (filter) {
case TASKS_BY_TYPE_FILTERS.LABEL:
state.selectedLabelIds = toggleSelectedLabel({ selectedLabelIds, value });
break;
case TASKS_BY_TYPE_FILTERS.SUBJECT:
state.subject = value;
break;
default:
break;
}
},
};
import { TASKS_BY_TYPE_SUBJECT_ISSUE } from '../../../constants';
export default () => ({
isLoadingTasksByTypeChart: false,
isLoadingTasksByTypeChartTopLabels: false,
subject: TASKS_BY_TYPE_SUBJECT_ISSUE,
selectedLabelIds: [],
topRankedLabels: [],
data: [],
});
...@@ -22,21 +22,10 @@ export const SHOW_CUSTOM_STAGE_FORM = 'SHOW_CUSTOM_STAGE_FORM'; ...@@ -22,21 +22,10 @@ export const SHOW_CUSTOM_STAGE_FORM = 'SHOW_CUSTOM_STAGE_FORM';
export const SHOW_EDIT_CUSTOM_STAGE_FORM = 'SHOW_EDIT_CUSTOM_STAGE_FORM'; export const SHOW_EDIT_CUSTOM_STAGE_FORM = 'SHOW_EDIT_CUSTOM_STAGE_FORM';
export const CLEAR_CUSTOM_STAGE_FORM_ERRORS = 'CLEAR_CUSTOM_STAGE_FORM_ERRORS'; export const CLEAR_CUSTOM_STAGE_FORM_ERRORS = 'CLEAR_CUSTOM_STAGE_FORM_ERRORS';
export const REQUEST_TOP_RANKED_GROUP_LABELS = 'REQUEST_TOP_RANKED_GROUP_LABELS';
export const RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS = 'RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS';
export const RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR = 'RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR';
export const REQUEST_GROUP_STAGES_AND_EVENTS = 'REQUEST_GROUP_STAGES_AND_EVENTS'; export const REQUEST_GROUP_STAGES_AND_EVENTS = 'REQUEST_GROUP_STAGES_AND_EVENTS';
export const RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS = 'RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS'; export const RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS = 'RECEIVE_GROUP_STAGES_AND_EVENTS_SUCCESS';
export const RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR = 'RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR'; export const RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR = 'RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR';
export const SET_TASKS_BY_TYPE_SUBJECT = 'SET_TASKS_BY_TYPE_SUBJECT';
export const SET_TASKS_BY_TYPE_LABELS = 'SET_TASKS_BY_TYPE_LABELS';
export const REQUEST_TASKS_BY_TYPE_DATA = 'REQUEST_TASKS_BY_TYPE_DATA';
export const RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS = 'RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS';
export const RECEIVE_TASKS_BY_TYPE_DATA_ERROR = 'RECEIVE_TASKS_BY_TYPE_DATA_ERROR';
export const REQUEST_CREATE_CUSTOM_STAGE = 'REQUEST_CREATE_CUSTOM_STAGE'; export const REQUEST_CREATE_CUSTOM_STAGE = 'REQUEST_CREATE_CUSTOM_STAGE';
export const RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS = 'RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS'; export const RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS = 'RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS';
export const RECEIVE_CREATE_CUSTOM_STAGE_ERROR = 'RECEIVE_CREATE_CUSTOM_STAGE_ERROR'; export const RECEIVE_CREATE_CUSTOM_STAGE_ERROR = 'RECEIVE_CREATE_CUSTOM_STAGE_ERROR';
...@@ -48,8 +37,6 @@ export const RECEIVE_UPDATE_STAGE_ERROR = 'RECEIVE_UPDATE_STAGE_ERROR'; ...@@ -48,8 +37,6 @@ export const RECEIVE_UPDATE_STAGE_ERROR = 'RECEIVE_UPDATE_STAGE_ERROR';
export const REQUEST_REMOVE_STAGE = 'REQUEST_REMOVE_STAGE'; export const REQUEST_REMOVE_STAGE = 'REQUEST_REMOVE_STAGE';
export const RECEIVE_REMOVE_STAGE_RESPONSE = 'RECEIVE_REMOVE_STAGE_RESPONSE'; export const RECEIVE_REMOVE_STAGE_RESPONSE = 'RECEIVE_REMOVE_STAGE_RESPONSE';
export const SET_TASKS_BY_TYPE_FILTERS = 'SET_TASKS_BY_TYPE_FILTERS';
export const INITIALIZE_CYCLE_ANALYTICS = 'INITIALIZE_CYCLE_ANALYTICS'; export const INITIALIZE_CYCLE_ANALYTICS = 'INITIALIZE_CYCLE_ANALYTICS';
export const INITIALIZE_CYCLE_ANALYTICS_SUCCESS = 'INITIALIZE_CYCLE_ANALYTICS_SUCCESS'; export const INITIALIZE_CYCLE_ANALYTICS_SUCCESS = 'INITIALIZE_CYCLE_ANALYTICS_SUCCESS';
......
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { transformRawStages, transformRawTasksByTypeData, toggleSelectedLabel } from '../utils'; import { transformRawStages } from '../utils';
import { TASKS_BY_TYPE_FILTERS } from '../constants';
export default { export default {
[types.SET_FEATURE_FLAGS](state, featureFlags) { [types.SET_FEATURE_FLAGS](state, featureFlags) {
...@@ -49,32 +48,6 @@ export default { ...@@ -49,32 +48,6 @@ export default {
state.isEmptyStage = true; state.isEmptyStage = true;
state.isLoadingStage = false; state.isLoadingStage = false;
}, },
[types.REQUEST_TOP_RANKED_GROUP_LABELS](state) {
state.isLoadingTasksByTypeChartTopLabels = true;
state.topRankedLabels = [];
state.tasksByType = {
...state.tasksByType,
selectedLabelIds: [],
};
},
[types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS](state, data = []) {
const { tasksByType } = state;
state.isLoadingTasksByTypeChartTopLabels = false;
state.topRankedLabels = data.map(convertObjectPropsToCamelCase);
state.tasksByType = {
...tasksByType,
selectedLabelIds: data.map(({ id }) => id),
};
},
[types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR](state) {
const { tasksByType } = state;
state.isLoadingTasksByTypeChartTopLabels = false;
state.topRankedLabels = [];
state.tasksByType = {
...tasksByType,
selectedLabelIds: [],
};
},
[types.REQUEST_STAGE_MEDIANS](state) { [types.REQUEST_STAGE_MEDIANS](state) {
state.medians = {}; state.medians = {};
}, },
...@@ -127,19 +100,6 @@ export default { ...@@ -127,19 +100,6 @@ export default {
convertObjectPropsToCamelCase(ev, { deep: true }), convertObjectPropsToCamelCase(ev, { deep: true }),
); );
}, },
[types.REQUEST_TASKS_BY_TYPE_DATA](state) {
state.isLoadingTasksByTypeChart = true;
},
[types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR](state) {
state.isLoadingTasksByTypeChart = false;
},
[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, data = []) {
state.isLoadingTasksByTypeChart = false;
state.tasksByType = {
...state.tasksByType,
data: transformRawTasksByTypeData(data),
};
},
[types.REQUEST_CREATE_CUSTOM_STAGE](state) { [types.REQUEST_CREATE_CUSTOM_STAGE](state) {
state.isSavingCustomStage = true; state.isSavingCustomStage = true;
state.customStageFormErrors = {}; state.customStageFormErrors = {};
...@@ -177,25 +137,6 @@ export default { ...@@ -177,25 +137,6 @@ export default {
[types.RECEIVE_REMOVE_STAGE_RESPONSE](state) { [types.RECEIVE_REMOVE_STAGE_RESPONSE](state) {
state.isLoading = false; state.isLoading = false;
}, },
[types.SET_TASKS_BY_TYPE_FILTERS](state, { filter, value }) {
const {
tasksByType: { selectedLabelIds, ...tasksByTypeRest },
} = state;
let updatedFilter = {};
switch (filter) {
case TASKS_BY_TYPE_FILTERS.LABEL:
updatedFilter = {
selectedLabelIds: toggleSelectedLabel({ selectedLabelIds, value }),
};
break;
case TASKS_BY_TYPE_FILTERS.SUBJECT:
updatedFilter = { subject: value };
break;
default:
break;
}
state.tasksByType = { ...tasksByTypeRest, selectedLabelIds, ...updatedFilter };
},
[types.INITIALIZE_CYCLE_ANALYTICS]( [types.INITIALIZE_CYCLE_ANALYTICS](
state, state,
{ {
......
import { TASKS_BY_TYPE_SUBJECT_ISSUE } from '../constants';
export default () => ({ export default () => ({
featureFlags: {}, featureFlags: {},
...@@ -8,8 +6,6 @@ export default () => ({ ...@@ -8,8 +6,6 @@ export default () => ({
isLoading: false, isLoading: false,
isLoadingStage: false, isLoadingStage: false,
isLoadingTasksByTypeChart: false,
isLoadingTasksByTypeChartTopLabels: false,
isEmptyStage: false, isEmptyStage: false,
errorCode: null, errorCode: null,
...@@ -28,16 +24,9 @@ export default () => ({ ...@@ -28,16 +24,9 @@ export default () => ({
stages: [], stages: [],
summary: [], summary: [],
topRankedLabels: [],
medians: {}, medians: {},
customStageFormEvents: [], customStageFormEvents: [],
customStageFormErrors: null, customStageFormErrors: null,
customStageFormInitialData: null, customStageFormInitialData: null,
tasksByType: {
subject: TASKS_BY_TYPE_SUBJECT_ISSUE,
selectedLabelIds: [],
data: [],
},
}); });
import { isNumber } from 'lodash'; import { isNumber } from 'lodash';
import dateFormat from 'dateformat'; import dateFormat from 'dateformat';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import httpStatus from '~/lib/utils/http_status';
import { convertToSnakeCase } from '~/lib/utils/text_utility'; import { convertToSnakeCase } from '~/lib/utils/text_utility';
import { hideFlash } from '~/flash'; import { hideFlash } from '~/flash';
import { import {
...@@ -329,3 +330,10 @@ export const getTasksByTypeData = ({ data = [], startDate = null, endDate = null ...@@ -329,3 +330,10 @@ export const getTasksByTypeData = ({ data = [], startDate = null, endDate = null
groupBy, groupBy,
}; };
}; };
export const handleErrorOrRethrow = ({ action, error }) => {
if (error?.response?.status === httpStatus.FORBIDDEN) {
throw error;
}
action();
};
import { createLocalVue, shallowMount, mount } from '@vue/test-utils'; import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Vue from 'vue';
import store from 'ee/analytics/cycle_analytics/store'; import store from 'ee/analytics/cycle_analytics/store';
import Component from 'ee/analytics/cycle_analytics/components/base.vue'; import Component from 'ee/analytics/cycle_analytics/components/base.vue';
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState } from '@gitlab/ui';
...@@ -291,16 +290,15 @@ describe('Cycle Analytics component', () => { ...@@ -291,16 +290,15 @@ describe('Cycle Analytics component', () => {
expect(second.classes('active')).toBe(false); expect(second.classes('active')).toBe(false);
}); });
it('can navigate to different stages', done => { it('can navigate to different stages', () => {
selectStageNavItem(2).trigger('click'); selectStageNavItem(2).trigger('click');
Vue.nextTick(() => { return wrapper.vm.$nextTick().then(() => {
const first = selectStageNavItem(0); const first = selectStageNavItem(0);
const third = selectStageNavItem(2); const third = selectStageNavItem(2);
expect(third.classes('active')).toBe(true); expect(third.classes('active')).toBe(true);
expect(first.classes('active')).toBe(false); expect(first.classes('active')).toBe(false);
done();
}); });
}); });
}); });
......
...@@ -10,7 +10,10 @@ import { ...@@ -10,7 +10,10 @@ import {
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { getDateInPast, getDatesInRange } from '~/lib/utils/datetime_utility'; import { getDateInPast, getDatesInRange } from '~/lib/utils/datetime_utility';
import { toYmd } from 'ee/analytics/shared/utils'; import { toYmd } from 'ee/analytics/shared/utils';
import { transformRawTasksByTypeData } from 'ee/analytics/cycle_analytics/utils'; import {
getTasksByTypeData,
transformRawTasksByTypeData,
} from 'ee/analytics/cycle_analytics/utils';
const fixtureEndpoints = { const fixtureEndpoints = {
customizableCycleAnalyticsStagesAndEvents: 'analytics/value_stream_analytics/stages.json', // customizable stages and events endpoint customizableCycleAnalyticsStagesAndEvents: 'analytics/value_stream_analytics/stages.json', // customizable stages and events endpoint
...@@ -145,7 +148,7 @@ export const customStageFormErrors = convertObjectPropsToCamelCase(rawCustomStag ...@@ -145,7 +148,7 @@ export const customStageFormErrors = convertObjectPropsToCamelCase(rawCustomStag
const dateRange = getDatesInRange(startDate, endDate, toYmd); const dateRange = getDatesInRange(startDate, endDate, toYmd);
export const rawTasksByTypeData = getJSONFixture('analytics/type_of_work/tasks_by_type.json').map( export const apiTasksByTypeData = getJSONFixture('analytics/type_of_work/tasks_by_type.json').map(
labelData => { labelData => {
// add data points for our mock date range // add data points for our mock date range
const maxValue = 10; const maxValue = 10;
...@@ -157,7 +160,8 @@ export const rawTasksByTypeData = getJSONFixture('analytics/type_of_work/tasks_b ...@@ -157,7 +160,8 @@ export const rawTasksByTypeData = getJSONFixture('analytics/type_of_work/tasks_b
}, },
); );
export const transformedTasksByTypeData = transformRawTasksByTypeData(rawTasksByTypeData); export const rawTasksByTypeData = transformRawTasksByTypeData(apiTasksByTypeData);
export const transformedTasksByTypeData = getTasksByTypeData(apiTasksByTypeData);
export const tasksByTypeData = { export const tasksByTypeData = {
seriesNames: ['Cool label', 'Normal label'], seriesNames: ['Cool label', 'Normal label'],
......
...@@ -4,16 +4,11 @@ import testAction from 'helpers/vuex_action_helper'; ...@@ -4,16 +4,11 @@ import testAction from 'helpers/vuex_action_helper';
import * as getters from 'ee/analytics/cycle_analytics/store/getters'; import * as getters from 'ee/analytics/cycle_analytics/store/getters';
import * as actions from 'ee/analytics/cycle_analytics/store/actions'; import * as actions from 'ee/analytics/cycle_analytics/store/actions';
import * as types from 'ee/analytics/cycle_analytics/store/mutation_types'; import * as types from 'ee/analytics/cycle_analytics/store/mutation_types';
import {
TASKS_BY_TYPE_FILTERS,
TASKS_BY_TYPE_SUBJECT_ISSUE,
} from 'ee/analytics/cycle_analytics/constants';
import createFlash from '~/flash'; import createFlash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status'; import httpStatusCodes from '~/lib/utils/http_status';
import { import {
selectedGroup, selectedGroup,
allowedStages as stages, allowedStages as stages,
groupLabels,
startDate, startDate,
endDate, endDate,
customizableStagesAndEvents, customizableStagesAndEvents,
...@@ -180,87 +175,6 @@ describe('Cycle analytics actions', () => { ...@@ -180,87 +175,6 @@ describe('Cycle analytics actions', () => {
}); });
}); });
describe('fetchTopRankedGroupLabels', () => {
beforeEach(() => {
gon.api_version = 'v4';
state = { selectedGroup, tasksByType: { subject: TASKS_BY_TYPE_SUBJECT_ISSUE }, ...getters };
});
describe('succeeds', () => {
beforeEach(() => {
mock.onGet(endpoints.tasksByTypeTopLabelsData).replyOnce(200, groupLabels);
});
it('dispatches receiveTopRankedGroupLabelsSuccess if the request succeeds', () => {
return testAction(
actions.fetchTopRankedGroupLabels,
null,
state,
[],
[
{ type: 'requestTopRankedGroupLabels' },
{ type: 'receiveTopRankedGroupLabelsSuccess', payload: groupLabels },
],
);
});
describe('receiveTopRankedGroupLabelsSuccess', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
});
it(`commits the ${types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS} mutation and dispatches the 'fetchTasksByTypeData' action`, done => {
testAction(
actions.receiveTopRankedGroupLabelsSuccess,
null,
state,
[
{
type: types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS,
payload: null,
},
],
[{ type: 'fetchTasksByTypeData' }],
done,
);
});
});
});
describe('with an error', () => {
beforeEach(() => {
mock.onGet(endpoints.fetchTopRankedGroupLabels).replyOnce(404);
});
it('dispatches receiveTopRankedGroupLabelsError if the request fails', () => {
return testAction(
actions.fetchTopRankedGroupLabels,
null,
state,
[],
[
{ type: 'requestTopRankedGroupLabels' },
{ type: 'receiveTopRankedGroupLabelsError', payload: error },
],
);
});
});
describe('receiveTopRankedGroupLabelsError', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
});
it('flashes an error message if the request fails', () => {
actions.receiveTopRankedGroupLabelsError({
commit: () => {},
});
shouldFlashAMessage('There was an error fetching the top labels for the selected group');
});
});
});
describe('fetchCycleAnalyticsData', () => { describe('fetchCycleAnalyticsData', () => {
function mockFetchCycleAnalyticsAction(overrides = {}) { function mockFetchCycleAnalyticsAction(overrides = {}) {
const mocks = { const mocks = {
...@@ -845,31 +759,6 @@ describe('Cycle analytics actions', () => { ...@@ -845,31 +759,6 @@ describe('Cycle analytics actions', () => {
}); });
}); });
describe('setTasksByTypeFilters', () => {
const filter = TASKS_BY_TYPE_FILTERS.SUBJECT;
const value = 'issue';
it(`commits the ${types.SET_TASKS_BY_TYPE_FILTERS} mutation and dispatches 'fetchTopRankedGroupLabels'`, done => {
testAction(
actions.setTasksByTypeFilters,
{ filter, value },
{},
[
{
type: types.SET_TASKS_BY_TYPE_FILTERS,
payload: { filter, value },
},
],
[
{
type: 'fetchTopRankedGroupLabels',
},
],
done,
);
});
});
describe('createCustomStage', () => { describe('createCustomStage', () => {
describe('with valid data', () => { describe('with valid data', () => {
const customStageData = { const customStageData = {
......
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as rootGetters from 'ee/analytics/cycle_analytics/store/getters';
import * as getters from 'ee/analytics/cycle_analytics/store/modules/type_of_work/getters';
import * as actions from 'ee/analytics/cycle_analytics/store/modules/type_of_work/actions';
import * as types from 'ee/analytics/cycle_analytics/store/modules/type_of_work/mutation_types';
import {
TASKS_BY_TYPE_FILTERS,
TASKS_BY_TYPE_SUBJECT_ISSUE,
} from 'ee/analytics/cycle_analytics/constants';
import httpStatusCodes from '~/lib/utils/http_status';
import { groupLabels, endpoints, startDate, endDate } from '../../../mock_data';
import { shouldFlashAMessage } from '../../../helpers';
const error = new Error(`Request failed with status code ${httpStatusCodes.NOT_FOUND}`);
describe('Type of work actions', () => {
let mock;
let state = {
isLoadingTasksByTypeChart: false,
isLoadingTasksByTypeChartTopLabels: false,
subject: TASKS_BY_TYPE_SUBJECT_ISSUE,
topRankedLabels: [],
selectedLabelIds: [],
data: [],
};
const mockedState = {
...rootGetters,
...getters,
...state,
rootState: { startDate, endDate },
};
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
state = { ...mockedState, selectedGroup: null };
});
describe('fetchTopRankedGroupLabels', () => {
beforeEach(() => {
gon.api_version = 'v4';
state = { ...mockedState, subject: TASKS_BY_TYPE_SUBJECT_ISSUE };
});
describe('succeeds', () => {
beforeEach(() => {
mock.onGet(endpoints.tasksByTypeTopLabelsData).replyOnce(200, groupLabels);
});
it('dispatches receiveTopRankedGroupLabelsSuccess if the request succeeds', () => {
return testAction(
actions.fetchTopRankedGroupLabels,
null,
state,
[{ type: 'REQUEST_TOP_RANKED_GROUP_LABELS' }],
[{ type: 'receiveTopRankedGroupLabelsSuccess', payload: groupLabels }],
);
});
describe('receiveTopRankedGroupLabelsSuccess', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
});
it(`commits the ${types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS} mutation and dispatches the 'fetchTasksByTypeData' action`, () => {
return testAction(
actions.receiveTopRankedGroupLabelsSuccess,
null,
state,
[
{
type: types.RECEIVE_TOP_RANKED_GROUP_LABELS_SUCCESS,
payload: null,
},
],
[{ type: 'fetchTasksByTypeData' }],
);
});
});
});
describe('with an error', () => {
beforeEach(() => {
mock.onGet(endpoints.fetchTopRankedGroupLabels).replyOnce(404);
});
it('dispatches receiveTopRankedGroupLabelsError if the request fails', () => {
return testAction(
actions.fetchTopRankedGroupLabels,
null,
state,
[{ type: 'REQUEST_TOP_RANKED_GROUP_LABELS' }],
[{ type: 'receiveTopRankedGroupLabelsError', payload: error }],
);
});
});
describe('receiveTopRankedGroupLabelsError', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
});
it('flashes an error message if the request fails', () => {
actions.receiveTopRankedGroupLabelsError({
commit: () => {},
});
shouldFlashAMessage('There was an error fetching the top labels for the selected group');
});
});
});
describe('setTasksByTypeFilters', () => {
const filter = TASKS_BY_TYPE_FILTERS.SUBJECT;
const value = 'issue';
it(`commits the ${types.SET_TASKS_BY_TYPE_FILTERS} mutation and dispatches 'fetchTasksByTypeData'`, () => {
return testAction(
actions.setTasksByTypeFilters,
{ filter, value },
{},
[
{
type: types.SET_TASKS_BY_TYPE_FILTERS,
payload: { filter, value },
},
],
[
{
type: 'fetchTasksByTypeData',
},
],
);
});
});
});
import { tasksByTypeChartData } from 'ee/analytics/cycle_analytics/store/modules/type_of_work/getters';
import {
rawTasksByTypeData,
transformedTasksByTypeData,
startDate,
endDate,
} from '../../../mock_data';
describe('Type of work getters', () => {
describe('tasksByTypeChartData', () => {
const rootState = { startDate, endDate };
describe('with data', () => {
it('correctly transforms the raw task by type data', () => {
expect(tasksByTypeChartData(rawTasksByTypeData, null, rootState)).toEqual(
transformedTasksByTypeData,
);
});
});
describe('with no data', () => {
it('returns all required properties', () => {
expect(tasksByTypeChartData()).toEqual({ groupBy: [], data: [], seriesNames: [] });
});
});
});
});
import mutations from 'ee/analytics/cycle_analytics/store/modules/type_of_work/mutations';
import * as types from 'ee/analytics/cycle_analytics/store/modules/type_of_work/mutation_types';
import { TASKS_BY_TYPE_FILTERS } from 'ee/analytics/cycle_analytics/constants';
import { apiTasksByTypeData, rawTasksByTypeData } from '../../../mock_data';
let state = null;
describe('Cycle analytics mutations', () => {
beforeEach(() => {
state = {};
});
afterEach(() => {
state = null;
});
it.each`
mutation | stateKey | value
${types.REQUEST_TOP_RANKED_GROUP_LABELS} | ${'topRankedLabels'} | ${[]}
${types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR} | ${'topRankedLabels'} | ${[]}
${types.REQUEST_TASKS_BY_TYPE_DATA} | ${'isLoadingTasksByTypeChart'} | ${true}
${types.RECEIVE_TASKS_BY_TYPE_DATA_ERROR} | ${'isLoadingTasksByTypeChart'} | ${false}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state);
expect(state[stateKey]).toEqual(value);
});
describe(`${types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS}`, () => {
it('sets isLoadingTasksByTypeChart to false', () => {
mutations[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, {});
expect(state.isLoadingTasksByTypeChart).toEqual(false);
});
it('sets data to the raw returned chart data', () => {
state = { data: null };
mutations[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, apiTasksByTypeData);
expect(state.data).toEqual(rawTasksByTypeData);
});
});
describe(`${types.SET_TASKS_BY_TYPE_FILTERS}`, () => {
it('will update the tasksByType state key', () => {
state = {};
const subjectFilter = { filter: TASKS_BY_TYPE_FILTERS.SUBJECT, value: 'cool-subject' };
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, subjectFilter);
expect(state.subject).toEqual('cool-subject');
});
it('will toggle the specified label id in the selectedLabelIds state key', () => {
state = {
selectedLabelIds: [10, 20, 30],
};
const labelFilter = { filter: TASKS_BY_TYPE_FILTERS.LABEL, value: 20 };
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, labelFilter);
expect(state.selectedLabelIds).toEqual([10, 30]);
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, labelFilter);
expect(state.selectedLabelIds).toEqual([10, 30, 20]);
});
});
});
import mutations from 'ee/analytics/cycle_analytics/store/mutations'; import mutations from 'ee/analytics/cycle_analytics/store/mutations';
import * as types from 'ee/analytics/cycle_analytics/store/mutation_types'; import * as types from 'ee/analytics/cycle_analytics/store/mutation_types';
import { TASKS_BY_TYPE_FILTERS } from 'ee/analytics/cycle_analytics/constants';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { import {
...@@ -15,8 +14,6 @@ import { ...@@ -15,8 +14,6 @@ import {
startDate, startDate,
endDate, endDate,
customizableStagesAndEvents, customizableStagesAndEvents,
rawTasksByTypeData,
transformedTasksByTypeData,
selectedProjects, selectedProjects,
} from '../mock_data'; } from '../mock_data';
...@@ -47,8 +44,6 @@ describe('Cycle analytics mutations', () => { ...@@ -47,8 +44,6 @@ describe('Cycle analytics mutations', () => {
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true} ${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false} ${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'isLoading'} | ${true} ${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'isLoading'} | ${true}
${types.REQUEST_TOP_RANKED_GROUP_LABELS} | ${'topRankedLabels'} | ${[]}
${types.RECEIVE_TOP_RANKED_GROUP_LABELS_ERROR} | ${'topRankedLabels'} | ${[]}
${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'stages'} | ${[]} ${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'stages'} | ${[]}
${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'stages'} | ${[]} ${types.REQUEST_GROUP_STAGES_AND_EVENTS} | ${'stages'} | ${[]}
${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'customStageFormEvents'} | ${[]} ${types.RECEIVE_GROUP_STAGES_AND_EVENTS_ERROR} | ${'customStageFormEvents'} | ${[]}
...@@ -57,8 +52,6 @@ describe('Cycle analytics mutations', () => { ...@@ -57,8 +52,6 @@ describe('Cycle analytics mutations', () => {
${types.RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS} | ${'isSavingCustomStage'} | ${false} ${types.RECEIVE_CREATE_CUSTOM_STAGE_SUCCESS} | ${'isSavingCustomStage'} | ${false}
${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'isSavingCustomStage'} | ${false} ${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'isSavingCustomStage'} | ${false}
${types.RECEIVE_CREATE_CUSTOM_STAGE_ERROR} | ${'customStageFormErrors'} | ${{}} ${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.REQUEST_UPDATE_STAGE} | ${'isLoading'} | ${true}
${types.REQUEST_UPDATE_STAGE} | ${'isSavingCustomStage'} | ${true} ${types.REQUEST_UPDATE_STAGE} | ${'isSavingCustomStage'} | ${true}
${types.REQUEST_UPDATE_STAGE} | ${'customStageFormErrors'} | ${null} ${types.REQUEST_UPDATE_STAGE} | ${'customStageFormErrors'} | ${null}
...@@ -176,21 +169,6 @@ describe('Cycle analytics mutations', () => { ...@@ -176,21 +169,6 @@ describe('Cycle analytics mutations', () => {
}); });
}); });
describe(`${types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS}`, () => {
it('sets isLoadingTasksByTypeChart to false', () => {
mutations[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, {});
expect(state.isLoadingTasksByTypeChart).toEqual(false);
});
it('sets tasksByType.data to the raw returned chart data', () => {
state = { tasksByType: { data: null } };
mutations[types.RECEIVE_TASKS_BY_TYPE_DATA_SUCCESS](state, rawTasksByTypeData);
expect(state.tasksByType.data).toEqual(transformedTasksByTypeData);
});
});
describe(`${types.RECEIVE_STAGE_MEDIANS_SUCCESS}`, () => { describe(`${types.RECEIVE_STAGE_MEDIANS_SUCCESS}`, () => {
it('sets each id as a key in the median object with the corresponding value', () => { it('sets each id as a key in the median object with the corresponding value', () => {
const stateWithData = { const stateWithData = {
...@@ -206,29 +184,6 @@ describe('Cycle analytics mutations', () => { ...@@ -206,29 +184,6 @@ describe('Cycle analytics mutations', () => {
}); });
}); });
describe(`${types.SET_TASKS_BY_TYPE_FILTERS}`, () => {
it('will update the tasksByType state key', () => {
state = { tasksByType: {} };
const subjectFilter = { filter: TASKS_BY_TYPE_FILTERS.SUBJECT, value: 'cool-subject' };
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, subjectFilter);
expect(state.tasksByType).toEqual({ subject: 'cool-subject' });
});
it('will toggle the specified label id in the tasksByType.selectedLabelIds state key', () => {
state = {
tasksByType: { selectedLabelIds: [10, 20, 30] },
};
const labelFilter = { filter: TASKS_BY_TYPE_FILTERS.LABEL, value: 20 };
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, labelFilter);
expect(state.tasksByType).toEqual({ selectedLabelIds: [10, 30] });
mutations[types.SET_TASKS_BY_TYPE_FILTERS](state, labelFilter);
expect(state.tasksByType).toEqual({ selectedLabelIds: [10, 30, 20] });
});
});
describe(`${types.INITIALIZE_CYCLE_ANALYTICS}`, () => { describe(`${types.INITIALIZE_CYCLE_ANALYTICS}`, () => {
const initialData = { const initialData = {
group: { fullPath: 'cool-group' }, group: { fullPath: 'cool-group' },
......
...@@ -32,7 +32,7 @@ import { ...@@ -32,7 +32,7 @@ import {
endDate, endDate,
issueStage, issueStage,
rawCustomStage, rawCustomStage,
transformedTasksByTypeData, rawTasksByTypeData,
} from './mock_data'; } from './mock_data';
const labelEventIds = labelEvents.map(ev => ev.identifier); const labelEventIds = labelEvents.map(ev => ev.identifier);
...@@ -239,9 +239,9 @@ describe('Cycle analytics utils', () => { ...@@ -239,9 +239,9 @@ describe('Cycle analytics utils', () => {
const groupBy = getDatesInRange(startDate, endDate, toYmd); const groupBy = getDatesInRange(startDate, endDate, toYmd);
// only return the values, drop the date which is the first paramater // only return the values, drop the date which is the first paramater
const extractSeriesValues = ({ series }) => series.map(kv => kv[1]); const extractSeriesValues = ({ series }) => series.map(kv => kv[1]);
const data = transformedTasksByTypeData.map(extractSeriesValues); const data = rawTasksByTypeData.map(extractSeriesValues);
const labels = transformedTasksByTypeData.map(d => { const labels = rawTasksByTypeData.map(d => {
const { label } = d; const { label } = d;
return label.title; return label.title;
}); });
...@@ -257,7 +257,7 @@ describe('Cycle analytics utils', () => { ...@@ -257,7 +257,7 @@ describe('Cycle analytics utils', () => {
describe('with data', () => { describe('with data', () => {
beforeEach(() => { beforeEach(() => {
transformed = getTasksByTypeData({ data: transformedTasksByTypeData, startDate, endDate }); transformed = getTasksByTypeData({ data: rawTasksByTypeData, startDate, endDate });
}); });
it('will return an object with the properties needed for the chart', () => { it('will return an object with the properties needed for the chart', () => {
......
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