summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Hughes <me@iamphill.com>2018-05-11 10:37:10 +0100
committerPhil Hughes <me@iamphill.com>2018-05-25 12:55:37 +0100
commita57e43dd8cf29b7574fcab63948fa2aaca1c00b7 (patch)
treef1c7fe9289659459d243876c73c0b6b7f1b0d622
parentd6a7a111ff3cc0bd4681615fc97c7b2a90729444 (diff)
downloadgitlab-ce-a57e43dd8cf29b7574fcab63948fa2aaca1c00b7.tar.gz
Show merge requests in web IDE
Closes #45184
-rw-r--r--app/assets/javascripts/api.js7
-rw-r--r--app/assets/javascripts/ide/stores/index.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/actions.js22
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/constants.js5
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/index.js10
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/mutation_types.js3
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/mutations.js17
-rw-r--r--app/assets/javascripts/ide/stores/modules/merge_requests/state.js7
-rw-r--r--changelogs/unreleased/ide-list-merge-requests.yml5
-rw-r--r--spec/javascripts/ide/mock_data.js8
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js144
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js41
12 files changed, 271 insertions, 0 deletions
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',
+ },
+ ]);
+ });
+ });
+});