Commit 47c29d9e authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch '13076-fetch-group-labels-after-group-selection' into 'master'

Fetch group labels after group selection

See merge request gitlab-org/gitlab!18616
parents 8418dba4 ed446ea2
...@@ -45,7 +45,6 @@ export default { ...@@ -45,7 +45,6 @@ export default {
...mapState([ ...mapState([
'isLoading', 'isLoading',
'isLoadingStage', 'isLoadingStage',
'isLoadingStageForm',
'isEmptyStage', 'isEmptyStage',
'isAddingCustomStage', 'isAddingCustomStage',
'selectedGroup', 'selectedGroup',
...@@ -84,7 +83,7 @@ export default { ...@@ -84,7 +83,7 @@ export default {
}, },
methods: { methods: {
...mapActions([ ...mapActions([
'fetchCustomStageFormData', 'fetchGroupLabels',
'fetchCycleAnalyticsData', 'fetchCycleAnalyticsData',
'fetchStageData', 'fetchStageData',
'setCycleAnalyticsDataEndpoint', 'setCycleAnalyticsDataEndpoint',
...@@ -95,12 +94,14 @@ export default { ...@@ -95,12 +94,14 @@ export default {
'fetchStageData', 'fetchStageData',
'setSelectedStageName', 'setSelectedStageName',
'hideCustomStageForm', 'hideCustomStageForm',
'showCustomStageForm',
'setDateRange', 'setDateRange',
]), ]),
onGroupSelect(group) { onGroupSelect(group) {
this.setCycleAnalyticsDataEndpoint(group.full_path); this.setCycleAnalyticsDataEndpoint(group.full_path);
this.setSelectedGroup(group); this.setSelectedGroup(group);
this.fetchCycleAnalyticsData(); this.fetchCycleAnalyticsData();
this.fetchGroupLabels(this.currentGroupPath);
}, },
onProjectsSelect(projects) { onProjectsSelect(projects) {
const projectIds = projects.map(value => value.id); const projectIds = projects.map(value => value.id);
...@@ -114,7 +115,7 @@ export default { ...@@ -114,7 +115,7 @@ export default {
this.fetchStageData(this.currentStage.name); this.fetchStageData(this.currentStage.name);
}, },
onShowAddStageForm() { onShowAddStageForm() {
this.fetchCustomStageFormData(this.currentGroupPath); this.showCustomStageForm();
}, },
initDateRange() { initDateRange() {
const endDate = new Date(Date.now()); const endDate = new Date(Date.now());
...@@ -201,7 +202,7 @@ export default { ...@@ -201,7 +202,7 @@ export default {
class="js-stage-table" class="js-stage-table"
:current-stage="currentStage" :current-stage="currentStage"
:stages="stages" :stages="stages"
:is-loading="isLoadingStage || isLoadingStageForm" :is-loading="isLoadingStage"
:is-empty-stage="isEmptyStage" :is-empty-stage="isEmptyStage"
:is-adding-custom-stage="isAddingCustomStage" :is-adding-custom-stage="isAddingCustomStage"
:current-stage-events="currentStageEvents" :current-stage-events="currentStageEvents"
......
...@@ -99,20 +99,22 @@ export const fetchCycleAnalyticsData = ({ state, dispatch }) => { ...@@ -99,20 +99,22 @@ export const fetchCycleAnalyticsData = ({ state, dispatch }) => {
}; };
export const hideCustomStageForm = ({ commit }) => commit(types.HIDE_CUSTOM_STAGE_FORM); export const hideCustomStageForm = ({ commit }) => commit(types.HIDE_CUSTOM_STAGE_FORM);
export const showCustomStageForm = ({ commit }) => commit(types.SHOW_CUSTOM_STAGE_FORM);
export const receiveCustomStageFormDataSuccess = ({ commit }, data) => export const receiveGroupLabelsSuccess = ({ commit }, data) =>
commit(types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS, data); commit(types.RECEIVE_GROUP_LABELS_SUCCESS, data);
export const receiveCustomStageFormDataError = ({ commit }, error) => {
commit(types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR, error); export const receiveGroupLabelsError = ({ commit }, error) => {
createFlash(__('There was an error fetching data for the form')); commit(types.RECEIVE_GROUP_LABELS_ERROR, error);
createFlash(__('There was an error fetching label data for the selected group'));
}; };
export const requestCustomStageFormData = ({ commit }) =>
commit(types.REQUEST_CUSTOM_STAGE_FORM_DATA);
export const fetchCustomStageFormData = ({ dispatch }, groupPath) => { export const requestGroupLabels = ({ commit }) => commit(types.REQUEST_GROUP_LABELS);
dispatch('requestCustomStageFormData');
export const fetchGroupLabels = ({ dispatch }, groupPath) => {
dispatch('requestGroupLabels');
return Api.groupLabels(groupPath) return Api.groupLabels(groupPath)
.then(data => dispatch('receiveCustomStageFormDataSuccess', data)) .then(data => dispatch('receiveGroupLabelsSuccess', data))
.catch(error => dispatch('receiveCustomStageFormDataError', error)); .catch(error => dispatch('receiveGroupLabelsError', error));
}; };
...@@ -8,5 +8,5 @@ export const defaultStage = state => (state.stages.length ? state.stages[0] : nu ...@@ -8,5 +8,5 @@ export const defaultStage = state => (state.stages.length ? state.stages[0] : nu
export const hasNoAccessError = state => state.errorCode === httpStatus.FORBIDDEN; export const hasNoAccessError = state => state.errorCode === httpStatus.FORBIDDEN;
export const currentGroupPath = state => export const currentGroupPath = ({ selectedGroup }) =>
state.selectedGroup && state.selectedGroup.full_path ? state.selectedGroup.full_path : null; selectedGroup && selectedGroup.fullPath ? selectedGroup.fullPath : null;
...@@ -16,7 +16,8 @@ export const RECEIVE_STAGE_DATA_SUCCESS = 'RECEIVE_STAGE_DATA_SUCCESS'; ...@@ -16,7 +16,8 @@ export const RECEIVE_STAGE_DATA_SUCCESS = 'RECEIVE_STAGE_DATA_SUCCESS';
export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR'; export const RECEIVE_STAGE_DATA_ERROR = 'RECEIVE_STAGE_DATA_ERROR';
export const HIDE_CUSTOM_STAGE_FORM = 'HIDE_CUSTOM_STAGE_FORM'; export const HIDE_CUSTOM_STAGE_FORM = 'HIDE_CUSTOM_STAGE_FORM';
export const SHOW_CUSTOM_STAGE_FORM = 'SHOW_CUSTOM_STAGE_FORM';
export const REQUEST_CUSTOM_STAGE_FORM_DATA = 'REQUEST_CUSTOM_STAGE_FORM_DATA'; export const REQUEST_GROUP_LABELS = 'REQUEST_GROUP_LABELS';
export const RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS = 'RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS'; export const RECEIVE_GROUP_LABELS_SUCCESS = 'RECEIVE_GROUP_LABELS_SUCCESS';
export const RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR = 'RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR'; export const RECEIVE_GROUP_LABELS_ERROR = 'RECEIVE_GROUP_LABELS_ERROR';
...@@ -11,7 +11,7 @@ export default { ...@@ -11,7 +11,7 @@ export default {
state.endpoints.stageData = `${state.endpoints.cycleAnalyticsData}/events/${stageSlug}.json`; state.endpoints.stageData = `${state.endpoints.cycleAnalyticsData}/events/${stageSlug}.json`;
}, },
[types.SET_SELECTED_GROUP](state, group) { [types.SET_SELECTED_GROUP](state, group) {
state.selectedGroup = group; state.selectedGroup = convertObjectPropsToCamelCase(group, { deep: true });
state.selectedProjectIds = []; state.selectedProjectIds = [];
}, },
[types.SET_SELECTED_PROJECTS](state, projectIds) { [types.SET_SELECTED_PROJECTS](state, projectIds) {
...@@ -71,20 +71,19 @@ export default { ...@@ -71,20 +71,19 @@ export default {
state.isEmptyStage = true; state.isEmptyStage = true;
state.isLoadingStage = false; state.isLoadingStage = false;
}, },
[types.REQUEST_CUSTOM_STAGE_FORM_DATA](state) { [types.REQUEST_GROUP_LABELS](state) {
state.isAddingCustomStage = true; state.labels = [];
state.isEmptyStage = false;
state.isLoadingStageForm = true;
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = false;
}, },
[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS](state, data = []) { [types.RECEIVE_GROUP_LABELS_SUCCESS](state, data = []) {
state.labels = data.map(convertObjectPropsToCamelCase); state.labels = data.map(convertObjectPropsToCamelCase);
state.isLoadingStageForm = false;
}, },
[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR](state) { [types.RECEIVE_GROUP_LABELS_ERROR](state) {
state.isLoadingStageForm = false;
state.labels = []; state.labels = [];
}, },
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = false;
},
[types.SHOW_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = true;
},
}; };
...@@ -9,7 +9,6 @@ export default () => ({ ...@@ -9,7 +9,6 @@ export default () => ({
isLoading: false, isLoading: false,
isLoadingStage: false, isLoadingStage: false,
isLoadingStageForm: false,
isEmptyStage: false, isEmptyStage: false,
errorCode: null, errorCode: null,
......
...@@ -12,6 +12,7 @@ import SummaryTable from 'ee/analytics/cycle_analytics/components/summary_table. ...@@ -12,6 +12,7 @@ import SummaryTable from 'ee/analytics/cycle_analytics/components/summary_table.
import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue'; import StageTable from 'ee/analytics/cycle_analytics/components/stage_table.vue';
import 'bootstrap'; import 'bootstrap';
import '~/gl_dropdown'; import '~/gl_dropdown';
import waitForPromises from 'helpers/wait_for_promises';
import * as mockData from '../mock_data'; import * as mockData from '../mock_data';
const noDataSvgPath = 'path/to/no/data'; const noDataSvgPath = 'path/to/no/data';
...@@ -293,4 +294,52 @@ describe('Cycle Analytics component', () => { ...@@ -293,4 +294,52 @@ describe('Cycle Analytics component', () => {
}); });
}); });
}); });
describe('with failed requests while loading', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
mock = new MockAdapter(axios);
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
mock.restore();
});
const findFlashError = () => document.querySelector('.flash-container .flash-text');
it('will display an error if the fetchCycleAnalyticsData request fails', () => {
expect(findFlashError()).toBeNull();
mock
.onGet('/groups/foo/-/labels')
.replyOnce(200, { response: { ...mockData.groupLabels } })
.onGet('/groups/foo/-/cycle_analytics')
.replyOnce(500, { response: { status: 500 } });
wrapper.vm.onGroupSelect(mockData.group);
return waitForPromises().then(() => {
expect(findFlashError().innerText.trim()).toEqual(
'There was an error while fetching cycle analytics data.',
);
});
});
it('will display an error if the fetchGroupLabels request fails', () => {
expect(findFlashError()).toBeNull();
mock.onGet('/groups/foo/-/labels').replyOnce(404, { response: { status: 404 } });
wrapper.vm.onGroupSelect(mockData.group);
return waitForPromises().then(() => {
expect(findFlashError().innerText.trim()).toEqual(
'There was an error fetching label data for the selected group',
);
});
});
});
}); });
...@@ -13,6 +13,7 @@ export const group = { ...@@ -13,6 +13,7 @@ export const group = {
id: 1, id: 1,
name: 'foo', name: 'foo',
path: 'foo', path: 'foo',
full_path: 'foo',
avatar_url: `${TEST_HOST}/images/home/nasa.svg`, avatar_url: `${TEST_HOST}/images/home/nasa.svg`,
}; };
......
...@@ -168,21 +168,21 @@ describe('Cycle analytics actions', () => { ...@@ -168,21 +168,21 @@ describe('Cycle analytics actions', () => {
}); });
}); });
describe('fetchCustomStageFormData', () => { describe('fetchGroupLabels', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(groupLabelsEndpoint).replyOnce(200, groupLabels); mock.onGet(groupLabelsEndpoint).replyOnce(200, groupLabels);
}); });
it('dispatches receiveCustomStageFormData if the request succeeds', done => { it('dispatches receiveGroupLabels if the request succeeds', done => {
testAction( testAction(
actions.fetchCustomStageFormData, actions.fetchGroupLabels,
groupPath, groupPath,
state, state,
[], [],
[ [
{ type: 'requestCustomStageFormData' }, { type: 'requestGroupLabels' },
{ {
type: 'receiveCustomStageFormDataSuccess', type: 'receiveGroupLabelsSuccess',
payload: groupLabels, payload: groupLabels,
}, },
], ],
...@@ -190,16 +190,16 @@ describe('Cycle analytics actions', () => { ...@@ -190,16 +190,16 @@ describe('Cycle analytics actions', () => {
); );
}); });
it('dispatches receiveCustomStageFormDataError if the request fails', done => { it('dispatches receiveGroupLabelsError if the request fails', done => {
testAction( testAction(
actions.fetchCustomStageFormData, actions.fetchGroupLabels,
'this-path-does-not-exist', 'this-path-does-not-exist',
state, state,
[], [],
[ [
{ type: 'requestCustomStageFormData' }, { type: 'requestGroupLabels' },
{ {
type: 'receiveCustomStageFormDataError', type: 'receiveGroupLabelsError',
payload: error, payload: error,
}, },
], ],
...@@ -207,16 +207,16 @@ describe('Cycle analytics actions', () => { ...@@ -207,16 +207,16 @@ describe('Cycle analytics actions', () => {
); );
}); });
describe('receiveCustomStageFormDataError', () => { describe('receiveGroupLabelsError', () => {
beforeEach(() => { beforeEach(() => {
setFixtures('<div class="flash-container"></div>'); setFixtures('<div class="flash-container"></div>');
}); });
it('flashes an error message if the request fails', () => { it('flashes an error message if the request fails', () => {
actions.receiveCustomStageFormDataError({ actions.receiveGroupLabelsError({
commit: () => {}, commit: () => {},
}); });
shouldFlashAnError('There was an error fetching data for the form'); shouldFlashAnError('There was an error fetching label data for the selected group');
}); });
}); });
}); });
......
...@@ -92,11 +92,11 @@ describe('Cycle analytics getters', () => { ...@@ -92,11 +92,11 @@ describe('Cycle analytics getters', () => {
describe('currentGroupPath', () => { describe('currentGroupPath', () => {
describe('with selectedGroup set', () => { describe('with selectedGroup set', () => {
it('returns the `full_path` value of the group', () => { it('returns the `fullPath` value of the group', () => {
const fullPath = 'cool-beans'; const fullPath = 'cool-beans';
state = { state = {
selectedGroup: { selectedGroup: {
full_path: fullPath, fullPath,
}, },
}; };
......
...@@ -29,17 +29,15 @@ describe('Cycle analytics mutations', () => { ...@@ -29,17 +29,15 @@ describe('Cycle analytics mutations', () => {
}); });
it.each` it.each`
mutation | stateKey | value mutation | stateKey | value
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true} ${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${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_CUSTOM_STAGE_FORM_DATA} | ${'isAddingCustomStage'} | ${true} ${types.HIDE_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${false}
${types.HIDE_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${false} ${types.SHOW_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${true}
${types.REQUEST_CUSTOM_STAGE_FORM_DATA} | ${'isLoadingStageForm'} | ${true} ${types.REQUEST_GROUP_LABELS} | ${'labels'} | ${[]}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR} | ${'isLoadingStageForm'} | ${false} ${types.RECEIVE_GROUP_LABELS_ERROR} | ${'labels'} | ${[]}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS} | ${'isLoadingStageForm'} | ${false}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR} | ${'labels'} | ${[]}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => { `('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state); mutations[mutation](state);
...@@ -47,17 +45,20 @@ describe('Cycle analytics mutations', () => { ...@@ -47,17 +45,20 @@ describe('Cycle analytics mutations', () => {
}); });
it.each` it.each`
mutation | payload | expectedState mutation | payload | expectedState
${types.SET_CYCLE_ANALYTICS_DATA_ENDPOINT} | ${'cool-beans'} | ${{ endpoints: { cycleAnalyticsData: '/groups/cool-beans/-/cycle_analytics' } }} ${types.SET_CYCLE_ANALYTICS_DATA_ENDPOINT} | ${'cool-beans'} | ${{ endpoints: { cycleAnalyticsData: '/groups/cool-beans/-/cycle_analytics' } }}
${types.SET_STAGE_DATA_ENDPOINT} | ${'rad-stage'} | ${{ endpoints: { stageData: '/fake/api/events/rad-stage.json' } }} ${types.SET_STAGE_DATA_ENDPOINT} | ${'rad-stage'} | ${{ endpoints: { stageData: '/fake/api/events/rad-stage.json' } }}
${types.SET_SELECTED_GROUP} | ${'cool-beans'} | ${{ selectedGroup: 'cool-beans', selectedProjectIds: [] }} ${types.SET_SELECTED_GROUP} | ${{ fullPath: 'cool-beans' }} | ${{ selectedGroup: { fullPath: 'cool-beans' }, selectedProjectIds: [] }}
${types.SET_SELECTED_PROJECTS} | ${[606, 707, 808, 909]} | ${{ selectedProjectIds: [606, 707, 808, 909] }} ${types.SET_SELECTED_PROJECTS} | ${[606, 707, 808, 909]} | ${{ selectedProjectIds: [606, 707, 808, 909] }}
${types.SET_DATE_RANGE} | ${{ startDate, endDate }} | ${{ startDate, endDate }} ${types.SET_DATE_RANGE} | ${{ startDate, endDate }} | ${{ startDate, endDate }}
${types.SET_SELECTED_STAGE_NAME} | ${'first-stage'} | ${{ selectedStageName: 'first-stage' }} ${types.SET_SELECTED_STAGE_NAME} | ${'first-stage'} | ${{ selectedStageName: 'first-stage' }}
`( `(
'$mutation with payload $payload will update state with $expectedState', '$mutation with payload $payload will update state with $expectedState',
({ mutation, payload, expectedState }) => { ({ mutation, payload, expectedState }) => {
state = { endpoints: { cycleAnalyticsData: '/fake/api' } }; state = {
endpoints: { cycleAnalyticsData: '/fake/api' },
selectedGroup: { fullPath: 'rad-stage' },
};
mutations[mutation](state, payload); mutations[mutation](state, payload);
expect(state).toMatchObject(expectedState); expect(state).toMatchObject(expectedState);
...@@ -90,9 +91,9 @@ describe('Cycle analytics mutations', () => { ...@@ -90,9 +91,9 @@ describe('Cycle analytics mutations', () => {
}); });
}); });
describe(`${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS}`, () => { describe(`${types.RECEIVE_GROUP_LABELS_SUCCESS}`, () => {
it('will set the labels state item with the camelCased custom stage events', () => { it('will set the labels state item with the camelCased group labels', () => {
mutations[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS](state, groupLabels); mutations[types.RECEIVE_GROUP_LABELS_SUCCESS](state, groupLabels);
expect(state.labels).toEqual(groupLabels.map(convertObjectPropsToCamelCase)); expect(state.labels).toEqual(groupLabels.map(convertObjectPropsToCamelCase));
}); });
......
...@@ -16671,7 +16671,7 @@ msgstr "" ...@@ -16671,7 +16671,7 @@ msgstr ""
msgid "There was an error fetching configuration for charts" msgid "There was an error fetching configuration for charts"
msgstr "" msgstr ""
msgid "There was an error fetching data for the form" msgid "There was an error fetching label data for the selected group"
msgstr "" msgstr ""
msgid "There was an error gathering the chart data" msgid "There was an error gathering the chart data"
......
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