Commit cda22d07 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'ide-even-more-improved-errors' into 'master'

Improve error message across IDE store modules

Closes #47323

See merge request gitlab-org/gitlab-ce!20272
parents 95f63bca 2848ed1f
import $ from 'jquery'; import $ from 'jquery';
import { sprintf, __ } from '~/locale'; import { sprintf, __ } from '~/locale';
import flash from '~/flash'; import flash from '~/flash';
import { stripHtml } from '~/lib/utils/text_utility';
import * as rootTypes from '../../mutation_types'; import * as rootTypes from '../../mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from '../../utils'; import { createCommitPayload, createNewMergeRequestUrl } from '../../utils';
import router from '../../../ide_router'; import router from '../../../ide_router';
...@@ -198,11 +197,18 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ...@@ -198,11 +197,18 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
if (err.response.status === 400) { if (err.response.status === 400) {
$('#ide-create-branch-modal').modal('show'); $('#ide-create-branch-modal').modal('show');
} else { } else {
let errMsg = __('Error committing changes. Please try again.'); dispatch(
if (err.response.data && err.response.data.message) { 'setErrorMessage',
errMsg += ` (${stripHtml(err.response.data.message)})`; {
} text: __('An error accured whilst committing your changes.'),
flash(errMsg, 'alert', document, null, false, true); action: () =>
dispatch('commitChanges').then(() =>
dispatch('setErrorMessage', null, { root: true }),
),
actionText: __('Please try again'),
},
{ root: true },
);
window.dispatchEvent(new Event('resize')); window.dispatchEvent(new Event('resize'));
} }
......
import { __ } from '../../../../locale'; import { __ } from '../../../../locale';
import Api from '../../../../api'; import Api from '../../../../api';
import flash from '../../../../flash';
import router from '../../../ide_router'; import router from '../../../ide_router';
import { scopes } from './constants'; import { scopes } from './constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -8,8 +7,20 @@ import * as rootTypes from '../../mutation_types'; ...@@ -8,8 +7,20 @@ import * as rootTypes from '../../mutation_types';
export const requestMergeRequests = ({ commit }, type) => export const requestMergeRequests = ({ commit }, type) =>
commit(types.REQUEST_MERGE_REQUESTS, type); commit(types.REQUEST_MERGE_REQUESTS, type);
export const receiveMergeRequestsError = ({ commit }, type) => { export const receiveMergeRequestsError = ({ commit, dispatch }, { type, search }) => {
flash(__('Error loading merge requests.')); dispatch(
'setErrorMessage',
{
text: __('Error loading merge requests.'),
action: payload =>
dispatch('fetchMergeRequests', payload).then(() =>
dispatch('setErrorMessage', null, { root: true }),
),
actionText: __('Please try again'),
actionPayload: { type, search },
},
{ root: true },
);
commit(types.RECEIVE_MERGE_REQUESTS_ERROR, type); commit(types.RECEIVE_MERGE_REQUESTS_ERROR, type);
}; };
export const receiveMergeRequestsSuccess = ({ commit }, { type, data }) => export const receiveMergeRequestsSuccess = ({ commit }, { type, data }) =>
...@@ -22,7 +33,7 @@ export const fetchMergeRequests = ({ dispatch, state: { state } }, { type, searc ...@@ -22,7 +33,7 @@ export const fetchMergeRequests = ({ dispatch, state: { state } }, { type, searc
Api.mergeRequests({ scope, state, search }) Api.mergeRequests({ scope, state, search })
.then(({ data }) => dispatch('receiveMergeRequestsSuccess', { type, data })) .then(({ data }) => dispatch('receiveMergeRequestsSuccess', { type, data }))
.catch(() => dispatch('receiveMergeRequestsError', type)); .catch(() => dispatch('receiveMergeRequestsError', { type, search }));
}; };
export const resetMergeRequests = ({ commit }, type) => commit(types.RESET_MERGE_REQUESTS, type); export const resetMergeRequests = ({ commit }, type) => commit(types.RESET_MERGE_REQUESTS, type);
......
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import axios from 'axios'; import axios from 'axios';
import httpStatus from '../../../../lib/utils/http_status';
import { __ } from '../../../../locale'; import { __ } from '../../../../locale';
import flash from '../../../../flash';
import Poll from '../../../../lib/utils/poll'; import Poll from '../../../../lib/utils/poll';
import service from '../../../services'; import service from '../../../services';
import { rightSidebarViews } from '../../../constants'; import { rightSidebarViews } from '../../../constants';
...@@ -18,10 +18,27 @@ export const stopPipelinePolling = () => { ...@@ -18,10 +18,27 @@ export const stopPipelinePolling = () => {
export const restartPipelinePolling = () => { export const restartPipelinePolling = () => {
if (eTagPoll) eTagPoll.restart(); if (eTagPoll) eTagPoll.restart();
}; };
export const forcePipelineRequest = () => {
if (eTagPoll) eTagPoll.makeRequest();
};
export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE); export const requestLatestPipeline = ({ commit }) => commit(types.REQUEST_LATEST_PIPELINE);
export const receiveLatestPipelineError = ({ commit, dispatch }) => { export const receiveLatestPipelineError = ({ commit, dispatch }, err) => {
flash(__('There was an error loading latest pipeline')); if (err.status !== httpStatus.NOT_FOUND) {
dispatch(
'setErrorMessage',
{
text: __('An error occured whilst fetching the latest pipline.'),
action: () =>
dispatch('forcePipelineRequest').then(() =>
dispatch('setErrorMessage', null, { root: true }),
),
actionText: __('Please try again'),
actionPayload: null,
},
{ root: true },
);
}
commit(types.RECEIVE_LASTEST_PIPELINE_ERROR); commit(types.RECEIVE_LASTEST_PIPELINE_ERROR);
dispatch('stopPipelinePolling'); dispatch('stopPipelinePolling');
}; };
...@@ -46,7 +63,7 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => { ...@@ -46,7 +63,7 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
method: 'lastCommitPipelines', method: 'lastCommitPipelines',
data: { getters: rootGetters }, data: { getters: rootGetters },
successCallback: ({ data }) => dispatch('receiveLatestPipelineSuccess', data), successCallback: ({ data }) => dispatch('receiveLatestPipelineSuccess', data),
errorCallback: () => dispatch('receiveLatestPipelineError'), errorCallback: err => dispatch('receiveLatestPipelineError', err),
}); });
if (!Visibility.hidden()) { if (!Visibility.hidden()) {
...@@ -63,9 +80,21 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => { ...@@ -63,9 +80,21 @@ export const fetchLatestPipeline = ({ dispatch, rootGetters }) => {
}; };
export const requestJobs = ({ commit }, id) => commit(types.REQUEST_JOBS, id); export const requestJobs = ({ commit }, id) => commit(types.REQUEST_JOBS, id);
export const receiveJobsError = ({ commit }, id) => { export const receiveJobsError = ({ commit, dispatch }, stage) => {
flash(__('There was an error loading jobs')); dispatch(
commit(types.RECEIVE_JOBS_ERROR, id); 'setErrorMessage',
{
text: __('An error occured whilst loading the pipelines jobs.'),
action: payload =>
dispatch('fetchJobs', payload).then(() =>
dispatch('setErrorMessage', null, { root: true }),
),
actionText: __('Please try again'),
actionPayload: stage,
},
{ root: true },
);
commit(types.RECEIVE_JOBS_ERROR, stage.id);
}; };
export const receiveJobsSuccess = ({ commit }, { id, data }) => export const receiveJobsSuccess = ({ commit }, { id, data }) =>
commit(types.RECEIVE_JOBS_SUCCESS, { id, data }); commit(types.RECEIVE_JOBS_SUCCESS, { id, data });
...@@ -76,7 +105,7 @@ export const fetchJobs = ({ dispatch }, stage) => { ...@@ -76,7 +105,7 @@ export const fetchJobs = ({ dispatch }, stage) => {
axios axios
.get(stage.dropdownPath) .get(stage.dropdownPath)
.then(({ data }) => dispatch('receiveJobsSuccess', { id: stage.id, data })) .then(({ data }) => dispatch('receiveJobsSuccess', { id: stage.id, data }))
.catch(() => dispatch('receiveJobsError', stage.id)); .catch(() => dispatch('receiveJobsError', stage));
}; };
export const toggleStageCollapsed = ({ commit }, stageId) => export const toggleStageCollapsed = ({ commit }, stageId) =>
...@@ -90,8 +119,18 @@ export const setDetailJob = ({ commit, dispatch }, job) => { ...@@ -90,8 +119,18 @@ export const setDetailJob = ({ commit, dispatch }, job) => {
}; };
export const requestJobTrace = ({ commit }) => commit(types.REQUEST_JOB_TRACE); export const requestJobTrace = ({ commit }) => commit(types.REQUEST_JOB_TRACE);
export const receiveJobTraceError = ({ commit }) => { export const receiveJobTraceError = ({ commit, dispatch }) => {
flash(__('Error fetching job trace')); dispatch(
'setErrorMessage',
{
text: __('An error occured whilst fetching the job trace.'),
action: () =>
dispatch('fetchJobTrace').then(() => dispatch('setErrorMessage', null, { root: true })),
actionText: __('Please try again'),
actionPayload: null,
},
{ root: true },
);
commit(types.RECEIVE_JOB_TRACE_ERROR); commit(types.RECEIVE_JOB_TRACE_ERROR);
}; };
export const receiveJobTraceSuccess = ({ commit }, data) => export const receiveJobTraceSuccess = ({ commit }, data) =>
......
...@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import state from '~/ide/stores/modules/merge_requests/state'; import state from '~/ide/stores/modules/merge_requests/state';
import * as types from '~/ide/stores/modules/merge_requests/mutation_types'; import * as types from '~/ide/stores/modules/merge_requests/mutation_types';
import actions, { import {
requestMergeRequests, requestMergeRequests,
receiveMergeRequestsError, receiveMergeRequestsError,
receiveMergeRequestsSuccess, receiveMergeRequestsSuccess,
...@@ -41,28 +41,26 @@ describe('IDE merge requests actions', () => { ...@@ -41,28 +41,26 @@ describe('IDE merge requests actions', () => {
}); });
describe('receiveMergeRequestsError', () => { describe('receiveMergeRequestsError', () => {
let flashSpy;
beforeEach(() => {
flashSpy = spyOnDependency(actions, 'flash');
});
it('should should commit error', done => { it('should should commit error', done => {
testAction( testAction(
receiveMergeRequestsError, receiveMergeRequestsError,
'created', { type: 'created', search: '' },
mockedState, mockedState,
[{ type: types.RECEIVE_MERGE_REQUESTS_ERROR, payload: 'created' }], [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR, payload: 'created' }],
[], [
{
type: 'setErrorMessage',
payload: {
text: 'Error loading merge requests.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: { type: 'created', search: '' },
},
},
],
done, done,
); );
}); });
it('creates flash message', () => {
receiveMergeRequestsError({ commit() {} }, 'created');
expect(flashSpy).toHaveBeenCalled();
});
}); });
describe('receiveMergeRequestsSuccess', () => { describe('receiveMergeRequestsSuccess', () => {
......
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import actions, { import {
requestLatestPipeline, requestLatestPipeline,
receiveLatestPipelineError, receiveLatestPipelineError,
receiveLatestPipelineSuccess, receiveLatestPipelineSuccess,
...@@ -59,7 +59,7 @@ describe('IDE pipelines actions', () => { ...@@ -59,7 +59,7 @@ describe('IDE pipelines actions', () => {
it('commits error', done => { it('commits error', done => {
testAction( testAction(
receiveLatestPipelineError, receiveLatestPipelineError,
null, { status: 404 },
mockedState, mockedState,
[{ type: types.RECEIVE_LASTEST_PIPELINE_ERROR }], [{ type: types.RECEIVE_LASTEST_PIPELINE_ERROR }],
[{ type: 'stopPipelinePolling' }], [{ type: 'stopPipelinePolling' }],
...@@ -67,12 +67,26 @@ describe('IDE pipelines actions', () => { ...@@ -67,12 +67,26 @@ describe('IDE pipelines actions', () => {
); );
}); });
it('creates flash message', () => { it('dispatches setErrorMessage is not 404', done => {
const flashSpy = spyOnDependency(actions, 'flash'); testAction(
receiveLatestPipelineError,
receiveLatestPipelineError({ commit() {}, dispatch() {} }); { status: 500 },
mockedState,
expect(flashSpy).toHaveBeenCalled(); [{ type: types.RECEIVE_LASTEST_PIPELINE_ERROR }],
[
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst fetching the latest pipline.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: null,
},
},
{ type: 'stopPipelinePolling' },
],
done,
);
}); });
}); });
...@@ -181,7 +195,10 @@ describe('IDE pipelines actions', () => { ...@@ -181,7 +195,10 @@ describe('IDE pipelines actions', () => {
new Promise(resolve => requestAnimationFrame(resolve)) new Promise(resolve => requestAnimationFrame(resolve))
.then(() => { .then(() => {
expect(dispatch.calls.argsFor(1)).toEqual(['receiveLatestPipelineError']); expect(dispatch.calls.argsFor(1)).toEqual([
'receiveLatestPipelineError',
jasmine.anything(),
]);
}) })
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
...@@ -199,21 +216,23 @@ describe('IDE pipelines actions', () => { ...@@ -199,21 +216,23 @@ describe('IDE pipelines actions', () => {
it('commits error', done => { it('commits error', done => {
testAction( testAction(
receiveJobsError, receiveJobsError,
1, { id: 1 },
mockedState, mockedState,
[{ type: types.RECEIVE_JOBS_ERROR, payload: 1 }], [{ type: types.RECEIVE_JOBS_ERROR, payload: 1 }],
[], [
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst loading the pipelines jobs.',
action: jasmine.anything(),
actionText: 'Please try again',
actionPayload: { id: 1 },
},
},
],
done, done,
); );
}); });
it('creates flash message', () => {
const flashSpy = spyOnDependency(actions, 'flash');
receiveJobsError({ commit() {} }, 1);
expect(flashSpy).toHaveBeenCalled();
});
}); });
describe('receiveJobsSuccess', () => { describe('receiveJobsSuccess', () => {
...@@ -268,7 +287,7 @@ describe('IDE pipelines actions', () => { ...@@ -268,7 +287,7 @@ describe('IDE pipelines actions', () => {
[], [],
[ [
{ type: 'requestJobs', payload: stage.id }, { type: 'requestJobs', payload: stage.id },
{ type: 'receiveJobsError', payload: stage.id }, { type: 'receiveJobsError', payload: stage },
], ],
done, done,
); );
...@@ -337,18 +356,20 @@ describe('IDE pipelines actions', () => { ...@@ -337,18 +356,20 @@ describe('IDE pipelines actions', () => {
null, null,
mockedState, mockedState,
[{ type: types.RECEIVE_JOB_TRACE_ERROR }], [{ type: types.RECEIVE_JOB_TRACE_ERROR }],
[], [
{
type: 'setErrorMessage',
payload: {
text: 'An error occured whilst fetching the job trace.',
action: jasmine.any(Function),
actionText: 'Please try again',
actionPayload: null,
},
},
],
done, done,
); );
}); });
it('creates flash message', () => {
const flashSpy = spyOnDependency(actions, 'flash');
receiveJobTraceError({ commit() {} });
expect(flashSpy).toHaveBeenCalled();
});
}); });
describe('receiveJobTraceSuccess', () => { describe('receiveJobTraceSuccess', () => {
......
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