From a57e43dd8cf29b7574fcab63948fa2aaca1c00b7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 11 May 2018 10:37:10 +0100 Subject: Show merge requests in web IDE Closes #45184 --- app/assets/javascripts/api.js | 7 + app/assets/javascripts/ide/stores/index.js | 2 + .../ide/stores/modules/merge_requests/actions.js | 22 ++++ .../ide/stores/modules/merge_requests/constants.js | 5 + .../ide/stores/modules/merge_requests/index.js | 10 ++ .../modules/merge_requests/mutation_types.js | 3 + .../ide/stores/modules/merge_requests/mutations.js | 17 +++ .../ide/stores/modules/merge_requests/state.js | 7 + changelogs/unreleased/ide-list-merge-requests.yml | 5 + spec/javascripts/ide/mock_data.js | 8 ++ .../stores/modules/merge_requests/actions_spec.js | 144 +++++++++++++++++++++ .../modules/merge_requests/mutations_spec.js | 41 ++++++ 12 files changed, 271 insertions(+) create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/actions.js create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/constants.js create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/index.js create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js create mode 100644 app/assets/javascripts/ide/stores/modules/merge_requests/state.js create mode 100644 changelogs/unreleased/ide-list-merge-requests.yml create mode 100644 spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js create mode 100644 spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index ce1069276ab..4aa52c446ff 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -11,6 +11,7 @@ const Api = { projectPath: '/api/:version/projects/:id', projectLabelsPath: '/:namespace_path/:project_path/labels', mergeRequestPath: '/api/:version/projects/:id/merge_requests/:mrid', + mergeRequestsPath: '/api/:version/merge_requests', mergeRequestChangesPath: '/api/:version/projects/:id/merge_requests/:mrid/changes', mergeRequestVersionsPath: '/api/:version/projects/:id/merge_requests/:mrid/versions', groupLabelsPath: '/groups/:namespace_path/-/labels', @@ -109,6 +110,12 @@ const Api = { return axios.get(url); }, + mergeRequests(params = {}) { + const url = Api.buildUrl(Api.mergeRequestsPath); + + return axios.get(url, { params }); + }, + mergeRequestChanges(projectPath, mergeRequestId) { const url = Api.buildUrl(Api.mergeRequestChangesPath) .replace(':id', encodeURIComponent(projectPath)) diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js index 699710055e3..457b57a30bb 100644 --- a/app/assets/javascripts/ide/stores/index.js +++ b/app/assets/javascripts/ide/stores/index.js @@ -6,6 +6,7 @@ import * as getters from './getters'; import mutations from './mutations'; import commitModule from './modules/commit'; import pipelines from './modules/pipelines'; +import mergeRequests from './modules/merge_requests'; Vue.use(Vuex); @@ -17,5 +18,6 @@ export default new Vuex.Store({ modules: { commit: commitModule, pipelines, + mergeRequests, }, }); diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js new file mode 100644 index 00000000000..856be0d73cd --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/actions.js @@ -0,0 +1,22 @@ +import { __ } from '../../../../locale'; +import Api from '../../../../api'; +import flash from '../../../../flash'; +import * as types from './mutation_types'; + +export const requestMergeRequests = ({ commit }) => commit(types.REQUEST_MERGE_REQUESTS); +export const receiveMergeRequestsError = ({ commit }) => { + flash(__('Error loading merge requests.')); + commit(types.RECEIVE_MERGE_REQUESTS_ERROR); +}; +export const receiveMergeRequestsSuccess = ({ commit }, data) => + commit(types.RECEIVE_MERGE_REQUESTS_SUCCESS, data); + +export const fetchMergeRequests = ({ dispatch, state }) => { + dispatch('requestMergeRequests'); + + Api.mergeRequests({ scope: state.scope, view: 'simple' }) + .then(({ data }) => { + dispatch('receiveMergeRequestsSuccess', data); + }) + .catch(() => dispatch('receiveMergeRequestsError')); +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js new file mode 100644 index 00000000000..c25edf11d96 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/constants.js @@ -0,0 +1,5 @@ +// eslint-disable-next-line import/prefer-default-export +export const scopes = { + assignedToMe: 'assigned-to-me', + createdByMe: 'created-by-me', +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/index.js b/app/assets/javascripts/ide/stores/modules/merge_requests/index.js new file mode 100644 index 00000000000..04e7e0f08f1 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/index.js @@ -0,0 +1,10 @@ +import state from './state'; +import * as actions from './actions'; +import mutations from './mutations'; + +export default { + namespaced: true, + state: state(), + actions, + mutations, +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js b/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js new file mode 100644 index 00000000000..83acc0ed33d --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js @@ -0,0 +1,3 @@ +export const REQUEST_MERGE_REQUESTS = 'REQUEST_MERGE_REQUESTS'; +export const RECEIVE_MERGE_REQUESTS_ERROR = 'RECEIVE_MERGE_REQUESTS_ERROR'; +export const RECEIVE_MERGE_REQUESTS_SUCCESS = 'RECEIVE_MERGE_REQUESTS_SUCCESS'; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js new file mode 100644 index 00000000000..82fb5c1346d --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js @@ -0,0 +1,17 @@ +/* eslint-disable no-param-reassign */ +import * as types from './mutation_types'; + +export default { + [types.REQUEST_MERGE_REQUESTS](state) { + state.isLoading = true; + }, + [types.RECEIVE_MERGE_REQUESTS_ERROR](state) { + state.isLoading = false; + }, + [types.RECEIVE_MERGE_REQUESTS_SUCCESS](state, data) { + state.mergeRequests = data.map(mergeRequest => ({ + id: mergeRequest.iid, + title: mergeRequest.title, + })); + }, +}; diff --git a/app/assets/javascripts/ide/stores/modules/merge_requests/state.js b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js new file mode 100644 index 00000000000..7ac555eef49 --- /dev/null +++ b/app/assets/javascripts/ide/stores/modules/merge_requests/state.js @@ -0,0 +1,7 @@ +import { scopes } from './constants'; + +export default () => ({ + isLoading: false, + mergeRequests: [], + scope: scopes.assignedToMe, +}); diff --git a/changelogs/unreleased/ide-list-merge-requests.yml b/changelogs/unreleased/ide-list-merge-requests.yml new file mode 100644 index 00000000000..2050ed23934 --- /dev/null +++ b/changelogs/unreleased/ide-list-merge-requests.yml @@ -0,0 +1,5 @@ +--- +title: Show authored and assigned merge requests in web IDE +merge_request: +author: +type: added diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js index c68ae050641..3c09ff36afa 100644 --- a/spec/javascripts/ide/mock_data.js +++ b/spec/javascripts/ide/mock_data.js @@ -93,3 +93,11 @@ export const fullPipelinesResponse = { ], }, }; + +export const mergeRequests = [ + { + iid: 1, + title: 'Test merge request', + project_id: 1, + }, +]; diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js new file mode 100644 index 00000000000..5d076577753 --- /dev/null +++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js @@ -0,0 +1,144 @@ +import MockAdapter from 'axios-mock-adapter'; +import axios from '~/lib/utils/axios_utils'; +import state from '~/ide/stores/modules/merge_requests/state'; +import * as types from '~/ide/stores/modules/merge_requests/mutation_types'; +import actions, { + requestMergeRequests, + receiveMergeRequestsError, + receiveMergeRequestsSuccess, + fetchMergeRequests, +} from '~/ide/stores/modules/merge_requests/actions'; +import { mergeRequests } from '../../../mock_data'; +import testAction from '../../../../helpers/vuex_action_helper'; + +describe('IDe merge requests actions', () => { + let mockedState; + let mock; + + beforeEach(() => { + mockedState = state(); + mock = new MockAdapter(axios); + }); + + afterEach(() => { + mock.restore(); + }); + + describe('requestMergeRequests', () => { + it('should should commit request', done => { + testAction( + requestMergeRequests, + null, + mockedState, + [{ type: types.REQUEST_MERGE_REQUESTS }], + [], + done, + ); + }); + }); + + describe('receiveMergeRequestsError', () => { + let flashSpy; + + beforeEach(() => { + flashSpy = spyOnDependency(actions, 'flash'); + }); + + it('should should commit error', done => { + testAction( + receiveMergeRequestsError, + null, + mockedState, + [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR }], + [], + done, + ); + }); + + it('creates flash message', () => { + receiveMergeRequestsError({ commit() {} }); + + expect(flashSpy).toHaveBeenCalled(); + }); + }); + + describe('receiveMergeRequestsSuccess', () => { + it('should commit received data', done => { + testAction( + receiveMergeRequestsSuccess, + 'data', + mockedState, + [{ type: types.RECEIVE_MERGE_REQUESTS_SUCCESS, payload: 'data' }], + [], + done, + ); + }); + }); + + describe('fetchMergeRequests', () => { + beforeEach(() => { + gon.api_version = 'v4'; + }); + + describe('success', () => { + beforeEach(() => { + mock.onGet(/\/api\/v4\/merge_requests(.*)$/).replyOnce(200, mergeRequests); + }); + + it('calls API with params from state', () => { + const apiSpy = spyOn(axios, 'get').and.callThrough(); + + fetchMergeRequests({ dispatch() {}, state: mockedState }); + + expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), { + params: { + scope: 'assigned-to-me', + view: 'simple', + }, + }); + }); + + it('dispatches request', done => { + testAction( + fetchMergeRequests, + null, + mockedState, + [], + [{ type: 'requestMergeRequests' }, { type: 'receiveMergeRequestsSuccess' }], + done, + ); + }); + + it('dispatches success with received data', done => { + testAction( + fetchMergeRequests, + null, + mockedState, + [], + [ + { type: 'requestMergeRequests' }, + { type: 'receiveMergeRequestsSuccess', payload: mergeRequests }, + ], + done, + ); + }); + }); + + describe('error', () => { + beforeEach(() => { + mock.onGet(/\/api\/v4\/merge_requests(.*)$/).replyOnce(500); + }); + + it('dispatches error', done => { + testAction( + fetchMergeRequests, + null, + mockedState, + [], + [{ type: 'requestMergeRequests' }, { type: 'receiveMergeRequestsError' }], + done, + ); + }); + }); + }); +}); diff --git a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js new file mode 100644 index 00000000000..8983bf65b31 --- /dev/null +++ b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js @@ -0,0 +1,41 @@ +import state from '~/ide/stores/modules/merge_requests/state'; +import mutations from '~/ide/stores/modules/merge_requests/mutations'; +import * as types from '~/ide/stores/modules/merge_requests/mutation_types'; +import { mergeRequests } from '../../../mock_data'; + +describe('IDE merge requests mutations', () => { + let mockedState; + + beforeEach(() => { + mockedState = state(); + }); + + describe(types.REQUEST_MERGE_REQUESTS, () => { + it('sets loading to true', () => { + mutations[types.REQUEST_MERGE_REQUESTS](mockedState); + + expect(mockedState.isLoading).toBe(true); + }); + }); + + describe(types.RECEIVE_MERGE_REQUESTS_ERROR, () => { + it('sets loading to false', () => { + mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState); + + expect(mockedState.isLoading).toBe(false); + }); + }); + + describe(types.RECEIVE_MERGE_REQUESTS_SUCCESS, () => { + it('sets merge requests', () => { + mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, mergeRequests); + + expect(mockedState.mergeRequests).toEqual([ + { + id: 1, + title: 'Test merge request', + }, + ]); + }); + }); +}); -- cgit v1.2.1