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 {
...mapState([
'isLoading',
'isLoadingStage',
'isLoadingStageForm',
'isEmptyStage',
'isAddingCustomStage',
'selectedGroup',
......@@ -84,7 +83,7 @@ export default {
},
methods: {
...mapActions([
'fetchCustomStageFormData',
'fetchGroupLabels',
'fetchCycleAnalyticsData',
'fetchStageData',
'setCycleAnalyticsDataEndpoint',
......@@ -95,12 +94,14 @@ export default {
'fetchStageData',
'setSelectedStageName',
'hideCustomStageForm',
'showCustomStageForm',
'setDateRange',
]),
onGroupSelect(group) {
this.setCycleAnalyticsDataEndpoint(group.full_path);
this.setSelectedGroup(group);
this.fetchCycleAnalyticsData();
this.fetchGroupLabels(this.currentGroupPath);
},
onProjectsSelect(projects) {
const projectIds = projects.map(value => value.id);
......@@ -114,7 +115,7 @@ export default {
this.fetchStageData(this.currentStage.name);
},
onShowAddStageForm() {
this.fetchCustomStageFormData(this.currentGroupPath);
this.showCustomStageForm();
},
initDateRange() {
const endDate = new Date(Date.now());
......@@ -201,7 +202,7 @@ export default {
class="js-stage-table"
:current-stage="currentStage"
:stages="stages"
:is-loading="isLoadingStage || isLoadingStageForm"
:is-loading="isLoadingStage"
:is-empty-stage="isEmptyStage"
:is-adding-custom-stage="isAddingCustomStage"
:current-stage-events="currentStageEvents"
......
......@@ -99,20 +99,22 @@ export const fetchCycleAnalyticsData = ({ state, dispatch }) => {
};
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) =>
commit(types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS, data);
export const receiveCustomStageFormDataError = ({ commit }, error) => {
commit(types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR, error);
createFlash(__('There was an error fetching data for the form'));
export const receiveGroupLabelsSuccess = ({ commit }, data) =>
commit(types.RECEIVE_GROUP_LABELS_SUCCESS, data);
export const receiveGroupLabelsError = ({ commit }, error) => {
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) => {
dispatch('requestCustomStageFormData');
export const requestGroupLabels = ({ commit }) => commit(types.REQUEST_GROUP_LABELS);
export const fetchGroupLabels = ({ dispatch }, groupPath) => {
dispatch('requestGroupLabels');
return Api.groupLabels(groupPath)
.then(data => dispatch('receiveCustomStageFormDataSuccess', data))
.catch(error => dispatch('receiveCustomStageFormDataError', error));
.then(data => dispatch('receiveGroupLabelsSuccess', data))
.catch(error => dispatch('receiveGroupLabelsError', error));
};
......@@ -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 currentGroupPath = state =>
state.selectedGroup && state.selectedGroup.full_path ? state.selectedGroup.full_path : null;
export const currentGroupPath = ({ selectedGroup }) =>
selectedGroup && selectedGroup.fullPath ? selectedGroup.fullPath : null;
......@@ -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 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 RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS = 'RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS';
export const RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR = 'RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR';
export const REQUEST_GROUP_LABELS = 'REQUEST_GROUP_LABELS';
export const RECEIVE_GROUP_LABELS_SUCCESS = 'RECEIVE_GROUP_LABELS_SUCCESS';
export const RECEIVE_GROUP_LABELS_ERROR = 'RECEIVE_GROUP_LABELS_ERROR';
......@@ -11,7 +11,7 @@ export default {
state.endpoints.stageData = `${state.endpoints.cycleAnalyticsData}/events/${stageSlug}.json`;
},
[types.SET_SELECTED_GROUP](state, group) {
state.selectedGroup = group;
state.selectedGroup = convertObjectPropsToCamelCase(group, { deep: true });
state.selectedProjectIds = [];
},
[types.SET_SELECTED_PROJECTS](state, projectIds) {
......@@ -71,20 +71,19 @@ export default {
state.isEmptyStage = true;
state.isLoadingStage = false;
},
[types.REQUEST_CUSTOM_STAGE_FORM_DATA](state) {
state.isAddingCustomStage = true;
state.isEmptyStage = false;
state.isLoadingStageForm = true;
},
[types.HIDE_CUSTOM_STAGE_FORM](state) {
state.isAddingCustomStage = false;
[types.REQUEST_GROUP_LABELS](state) {
state.labels = [];
},
[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS](state, data = []) {
[types.RECEIVE_GROUP_LABELS_SUCCESS](state, data = []) {
state.labels = data.map(convertObjectPropsToCamelCase);
state.isLoadingStageForm = false;
},
[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR](state) {
state.isLoadingStageForm = false;
[types.RECEIVE_GROUP_LABELS_ERROR](state) {
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 () => ({
isLoading: false,
isLoadingStage: false,
isLoadingStageForm: false,
isEmptyStage: false,
errorCode: null,
......
......@@ -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 'bootstrap';
import '~/gl_dropdown';
import waitForPromises from 'helpers/wait_for_promises';
import * as mockData from '../mock_data';
const noDataSvgPath = 'path/to/no/data';
......@@ -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 = {
id: 1,
name: 'foo',
path: 'foo',
full_path: 'foo',
avatar_url: `${TEST_HOST}/images/home/nasa.svg`,
};
......
......@@ -168,21 +168,21 @@ describe('Cycle analytics actions', () => {
});
});
describe('fetchCustomStageFormData', () => {
describe('fetchGroupLabels', () => {
beforeEach(() => {
mock.onGet(groupLabelsEndpoint).replyOnce(200, groupLabels);
});
it('dispatches receiveCustomStageFormData if the request succeeds', done => {
it('dispatches receiveGroupLabels if the request succeeds', done => {
testAction(
actions.fetchCustomStageFormData,
actions.fetchGroupLabels,
groupPath,
state,
[],
[
{ type: 'requestCustomStageFormData' },
{ type: 'requestGroupLabels' },
{
type: 'receiveCustomStageFormDataSuccess',
type: 'receiveGroupLabelsSuccess',
payload: groupLabels,
},
],
......@@ -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(
actions.fetchCustomStageFormData,
actions.fetchGroupLabels,
'this-path-does-not-exist',
state,
[],
[
{ type: 'requestCustomStageFormData' },
{ type: 'requestGroupLabels' },
{
type: 'receiveCustomStageFormDataError',
type: 'receiveGroupLabelsError',
payload: error,
},
],
......@@ -207,16 +207,16 @@ describe('Cycle analytics actions', () => {
);
});
describe('receiveCustomStageFormDataError', () => {
describe('receiveGroupLabelsError', () => {
beforeEach(() => {
setFixtures('<div class="flash-container"></div>');
});
it('flashes an error message if the request fails', () => {
actions.receiveCustomStageFormDataError({
actions.receiveGroupLabelsError({
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', () => {
describe('currentGroupPath', () => {
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';
state = {
selectedGroup: {
full_path: fullPath,
fullPath,
},
};
......
......@@ -29,17 +29,15 @@ describe('Cycle analytics mutations', () => {
});
it.each`
mutation | stateKey | value
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'isLoading'} | ${true}
${types.REQUEST_CUSTOM_STAGE_FORM_DATA} | ${'isAddingCustomStage'} | ${true}
${types.HIDE_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${false}
${types.REQUEST_CUSTOM_STAGE_FORM_DATA} | ${'isLoadingStageForm'} | ${true}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR} | ${'isLoadingStageForm'} | ${false}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS} | ${'isLoadingStageForm'} | ${false}
${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_ERROR} | ${'labels'} | ${[]}
mutation | stateKey | value
${types.REQUEST_STAGE_DATA} | ${'isLoadingStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isEmptyStage'} | ${true}
${types.RECEIVE_STAGE_DATA_ERROR} | ${'isLoadingStage'} | ${false}
${types.REQUEST_CYCLE_ANALYTICS_DATA} | ${'isLoading'} | ${true}
${types.HIDE_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${false}
${types.SHOW_CUSTOM_STAGE_FORM} | ${'isAddingCustomStage'} | ${true}
${types.REQUEST_GROUP_LABELS} | ${'labels'} | ${[]}
${types.RECEIVE_GROUP_LABELS_ERROR} | ${'labels'} | ${[]}
`('$mutation will set $stateKey=$value', ({ mutation, stateKey, value }) => {
mutations[mutation](state);
......@@ -47,17 +45,20 @@ describe('Cycle analytics mutations', () => {
});
it.each`
mutation | payload | expectedState
${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_SELECTED_GROUP} | ${'cool-beans'} | ${{ selectedGroup: 'cool-beans', selectedProjectIds: [] }}
${types.SET_SELECTED_PROJECTS} | ${[606, 707, 808, 909]} | ${{ selectedProjectIds: [606, 707, 808, 909] }}
${types.SET_DATE_RANGE} | ${{ startDate, endDate }} | ${{ startDate, endDate }}
${types.SET_SELECTED_STAGE_NAME} | ${'first-stage'} | ${{ selectedStageName: 'first-stage' }}
mutation | payload | expectedState
${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_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_DATE_RANGE} | ${{ startDate, endDate }} | ${{ startDate, endDate }}
${types.SET_SELECTED_STAGE_NAME} | ${'first-stage'} | ${{ selectedStageName: 'first-stage' }}
`(
'$mutation with payload $payload will update state with $expectedState',
({ mutation, payload, expectedState }) => {
state = { endpoints: { cycleAnalyticsData: '/fake/api' } };
state = {
endpoints: { cycleAnalyticsData: '/fake/api' },
selectedGroup: { fullPath: 'rad-stage' },
};
mutations[mutation](state, payload);
expect(state).toMatchObject(expectedState);
......@@ -90,9 +91,9 @@ describe('Cycle analytics mutations', () => {
});
});
describe(`${types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS}`, () => {
it('will set the labels state item with the camelCased custom stage events', () => {
mutations[types.RECEIVE_CUSTOM_STAGE_FORM_DATA_SUCCESS](state, groupLabels);
describe(`${types.RECEIVE_GROUP_LABELS_SUCCESS}`, () => {
it('will set the labels state item with the camelCased group labels', () => {
mutations[types.RECEIVE_GROUP_LABELS_SUCCESS](state, groupLabels);
expect(state.labels).toEqual(groupLabels.map(convertObjectPropsToCamelCase));
});
......
......@@ -16671,7 +16671,7 @@ msgstr ""
msgid "There was an error fetching configuration for charts"
msgstr ""
msgid "There was an error fetching data for the form"
msgid "There was an error fetching label data for the selected group"
msgstr ""
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