Commit aede6488 authored by Phil Hughes's avatar Phil Hughes

Merge branch 'backstage/ide-router-refactoring' into 'master'

Backstage/ide router refactoring

See merge request gitlab-org/gitlab-ce!21142
parents 00c474ae 0a3d18b0
...@@ -3,7 +3,6 @@ import VueRouter from 'vue-router'; ...@@ -3,7 +3,6 @@ import VueRouter from 'vue-router';
import { join as joinPath } from 'path'; import { join as joinPath } from 'path';
import flash from '~/flash'; import flash from '~/flash';
import store from './stores'; import store from './stores';
import { activityBarViews } from './constants';
Vue.use(VueRouter); Vue.use(VueRouter);
...@@ -74,101 +73,22 @@ router.beforeEach((to, from, next) => { ...@@ -74,101 +73,22 @@ router.beforeEach((to, from, next) => {
projectId: to.params.project, projectId: to.params.project,
}) })
.then(() => { .then(() => {
const fullProjectId = `${to.params.namespace}/${to.params.project}`; const basePath = to.params[0] || '';
const projectId = `${to.params.namespace}/${to.params.project}`;
const branchId = to.params.branchid; const branchId = to.params.branchid;
const mergeRequestId = to.params.mrid;
if (branchId) { if (branchId) {
const basePath = to.params[0] || ''; store.dispatch('openBranch', {
projectId,
store.dispatch('setCurrentBranchId', branchId);
store.dispatch('getBranchData', {
projectId: fullProjectId,
branchId, branchId,
basePath,
}); });
} else if (mergeRequestId) {
store store.dispatch('openMergeRequest', {
.dispatch('getFiles', { projectId,
projectId: fullProjectId, mergeRequestId,
branchId,
})
.then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(store.state.entries).find(
key => key === path && !store.state.entries[key].pending,
);
const treeEntry = store.state.entries[treeEntryKey];
if (treeEntry) {
store.dispatch('handleTreeEntryAction', treeEntry);
}
}
})
.catch(e => {
throw e;
});
} else if (to.params.mrid) {
store
.dispatch('getMergeRequestData', {
projectId: fullProjectId,
targetProjectId: to.query.target_project, targetProjectId: to.query.target_project,
mergeRequestId: to.params.mrid,
})
.then(mr => {
store.dispatch('setCurrentBranchId', mr.source_branch);
store.dispatch('getBranchData', {
projectId: fullProjectId,
branchId: mr.source_branch,
});
return store.dispatch('getFiles', {
projectId: fullProjectId,
branchId: mr.source_branch,
});
})
.then(() =>
store.dispatch('getMergeRequestVersions', {
projectId: fullProjectId,
targetProjectId: to.query.target_project,
mergeRequestId: to.params.mrid,
}),
)
.then(() =>
store.dispatch('getMergeRequestChanges', {
projectId: fullProjectId,
targetProjectId: to.query.target_project,
mergeRequestId: to.params.mrid,
}),
)
.then(mrChanges => {
if (mrChanges.changes.length) {
store.dispatch('updateActivityBarView', activityBarViews.review);
}
mrChanges.changes.forEach((change, ind) => {
const changeTreeEntry = store.state.entries[change.new_path];
if (changeTreeEntry) {
store.dispatch('setFileMrChange', {
file: changeTreeEntry,
mrChange: change,
});
if (ind < 10) {
store.dispatch('getFileData', {
path: change.new_path,
makeFileActive: ind === 0,
});
}
}
});
})
.catch(e => {
flash('Error while loading the merge request. Please try again.');
throw e;
}); });
} }
}) })
......
import { __ } from '../../../locale'; import flash from '~/flash';
import { __ } from '~/locale';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
import { activityBarViews } from '../../constants';
export const getMergeRequestData = ( export const getMergeRequestData = (
{ commit, dispatch, state }, { commit, dispatch, state },
...@@ -104,3 +106,67 @@ export const getMergeRequestVersions = ( ...@@ -104,3 +106,67 @@ export const getMergeRequestVersions = (
resolve(state.projects[projectId].mergeRequests[mergeRequestId].versions); resolve(state.projects[projectId].mergeRequests[mergeRequestId].versions);
} }
}); });
export const openMergeRequest = (
{ dispatch, state },
{ projectId, targetProjectId, mergeRequestId } = {},
) =>
dispatch('getMergeRequestData', {
projectId,
targetProjectId,
mergeRequestId,
})
.then(mr => {
dispatch('setCurrentBranchId', mr.source_branch);
dispatch('getBranchData', {
projectId,
branchId: mr.source_branch,
});
return dispatch('getFiles', {
projectId,
branchId: mr.source_branch,
});
})
.then(() =>
dispatch('getMergeRequestVersions', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(() =>
dispatch('getMergeRequestChanges', {
projectId,
targetProjectId,
mergeRequestId,
}),
)
.then(mrChanges => {
if (mrChanges.changes.length) {
dispatch('updateActivityBarView', activityBarViews.review);
}
mrChanges.changes.forEach((change, ind) => {
const changeTreeEntry = state.entries[change.new_path];
if (changeTreeEntry) {
dispatch('setFileMrChange', {
file: changeTreeEntry,
mrChange: change,
});
if (ind < 10) {
dispatch('getFileData', {
path: change.new_path,
makeFileActive: ind === 0,
});
}
}
});
})
.catch(e => {
flash(__('Error while loading the merge request. Please try again.'));
throw e;
});
...@@ -124,3 +124,35 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => { ...@@ -124,3 +124,35 @@ export const showBranchNotFoundError = ({ dispatch }, branchId) => {
actionPayload: branchId, actionPayload: branchId,
}); });
}; };
export const openBranch = (
{ dispatch, state },
{ projectId, branchId, basePath },
) => {
dispatch('setCurrentBranchId', branchId);
dispatch('getBranchData', {
projectId,
branchId,
});
return (
dispatch('getFiles', {
projectId,
branchId,
})
.then(() => {
if (basePath) {
const path = basePath.slice(-1) === '/' ? basePath.slice(0, -1) : basePath;
const treeEntryKey = Object.keys(state.entries).find(
key => key === path && !state.entries[key].pending,
);
const treeEntry = state.entries[treeEntryKey];
if (treeEntry) {
dispatch('handleTreeEntryAction', treeEntry);
}
}
})
);
};
...@@ -33,7 +33,4 @@ export const fetchBranches = ({ dispatch, rootGetters }, { search = '' }) => { ...@@ -33,7 +33,4 @@ export const fetchBranches = ({ dispatch, rootGetters }, { search = '' }) => {
export const resetBranches = ({ commit }) => commit(types.RESET_BRANCHES); export const resetBranches = ({ commit }) => commit(types.RESET_BRANCHES);
export const openBranch = ({ rootState, dispatch }, id) =>
dispatch('goToRoute', `/project/${rootState.currentProjectId}/edit/${id}`, { root: true });
export default () => {}; export default () => {};
...@@ -2451,6 +2451,9 @@ msgstr "" ...@@ -2451,6 +2451,9 @@ msgstr ""
msgid "Error updating todo status." msgid "Error updating todo status."
msgstr "" msgstr ""
msgid "Error while loading the merge request. Please try again."
msgstr ""
msgid "Estimated" msgid "Estimated"
msgstr "" msgstr ""
......
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 store from '~/ide/stores'; import store from '~/ide/stores';
import { import actions, {
getMergeRequestData, getMergeRequestData,
getMergeRequestChanges, getMergeRequestChanges,
getMergeRequestVersions, getMergeRequestVersions,
openMergeRequest,
} from '~/ide/stores/actions/merge_request'; } from '~/ide/stores/actions/merge_request';
import service from '~/ide/services'; import service from '~/ide/services';
import { activityBarViews } from '~/ide/constants';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
describe('IDE store merge request actions', () => { describe('IDE store merge request actions', () => {
...@@ -238,4 +240,101 @@ describe('IDE store merge request actions', () => { ...@@ -238,4 +240,101 @@ describe('IDE store merge request actions', () => {
}); });
}); });
}); });
describe('openMergeRequest', () => {
const mr = {
projectId: 'abcproject',
targetProjectId: 'defproject',
mergeRequestId: 2,
};
let testMergeRequest;
let testMergeRequestChanges;
beforeEach(() => {
testMergeRequest = {
source_branch: 'abcbranch',
};
testMergeRequestChanges = {
changes: [],
};
store.state.entries = {
foo: {},
bar: {},
};
spyOn(store, 'dispatch').and.callFake((type) => {
switch (type) {
case 'getMergeRequestData':
return Promise.resolve(testMergeRequest);
case 'getMergeRequestChanges':
return Promise.resolve(testMergeRequestChanges);
default:
return Promise.resolve();
}
});
});
it('dispatch actions for merge request data', done => {
openMergeRequest(store, mr)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['getMergeRequestData', mr],
['setCurrentBranchId', testMergeRequest.source_branch],
['getBranchData', {
projectId: mr.projectId,
branchId: testMergeRequest.source_branch,
}],
['getFiles', {
projectId: mr.projectId,
branchId: testMergeRequest.source_branch,
}],
['getMergeRequestVersions', mr],
['getMergeRequestChanges', mr],
]);
})
.then(done)
.catch(done.fail);
});
it('updates activity bar view and gets file data, if changes are found', done => {
testMergeRequestChanges.changes = [
{ new_path: 'foo' },
{ new_path: 'bar' },
];
openMergeRequest(store, mr)
.then(() => {
expect(store.dispatch).toHaveBeenCalledWith('updateActivityBarView', activityBarViews.review);
testMergeRequestChanges.changes.forEach((change, i) => {
expect(store.dispatch).toHaveBeenCalledWith('setFileMrChange', {
file: store.state.entries[change.new_path],
mrChange: change,
});
expect(store.dispatch).toHaveBeenCalledWith('getFileData', {
path: change.new_path,
makeFileActive: i === 0,
});
});
})
.then(done)
.catch(done.fail);
});
it('flashes message, if error', done => {
const flashSpy = spyOnDependency(actions, 'flash');
store.dispatch.and.returnValue(Promise.reject());
openMergeRequest(store, mr)
.then(() => {
fail('Expected openMergeRequest to throw an error');
})
.catch(() => {
expect(flashSpy).toHaveBeenCalledWith(jasmine.any(String));
})
.then(done)
.catch(done.fail);
});
});
}); });
...@@ -5,6 +5,7 @@ import { ...@@ -5,6 +5,7 @@ import {
showBranchNotFoundError, showBranchNotFoundError,
createNewBranchFromDefault, createNewBranchFromDefault,
getBranchData, getBranchData,
openBranch,
} from '~/ide/stores/actions'; } from '~/ide/stores/actions';
import store from '~/ide/stores'; import store from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
...@@ -224,4 +225,55 @@ describe('IDE store project actions', () => { ...@@ -224,4 +225,55 @@ describe('IDE store project actions', () => {
}); });
}); });
}); });
describe('openBranch', () => {
const branch = {
projectId: 'feature/lorem-ipsum',
branchId: '123-lorem',
};
beforeEach(() => {
store.state.entries = {
foo: { pending: false },
'foo/bar-pending': { pending: true },
'foo/bar': { pending: false },
};
spyOn(store, 'dispatch').and.returnValue(Promise.resolve());
});
it('dispatches branch actions', done => {
openBranch(store, branch)
.then(() => {
expect(store.dispatch.calls.allArgs()).toEqual([
['setCurrentBranchId', branch.branchId],
['getBranchData', branch],
['getFiles', branch],
]);
})
.then(done)
.catch(done.fail);
});
it('handles tree entry action, if basePath is given', done => {
openBranch(store, { ...branch, basePath: 'foo/bar/' })
.then(() => {
expect(store.dispatch).toHaveBeenCalledWith(
'handleTreeEntryAction',
store.state.entries['foo/bar'],
);
})
.then(done)
.catch(done.fail);
});
it('does not handle tree entry action, if entry is pending', done => {
openBranch(store, { ...branch, basePath: 'foo/bar-pending' })
.then(() => {
expect(store.dispatch).not.toHaveBeenCalledWith('handleTreeEntryAction', jasmine.anything());
})
.then(done)
.catch(done.fail);
});
});
}); });
...@@ -9,7 +9,6 @@ import { ...@@ -9,7 +9,6 @@ import {
receiveBranchesSuccess, receiveBranchesSuccess,
fetchBranches, fetchBranches,
resetBranches, resetBranches,
openBranch,
} from '~/ide/stores/modules/branches/actions'; } from '~/ide/stores/modules/branches/actions';
import { branches, projectData } from '../../../mock_data'; import { branches, projectData } from '../../../mock_data';
...@@ -174,20 +173,5 @@ describe('IDE branches actions', () => { ...@@ -174,20 +173,5 @@ describe('IDE branches actions', () => {
); );
}); });
}); });
describe('openBranch', () => {
it('dispatches goToRoute action with path', done => {
const branchId = branches[0].name;
const expectedPath = `/project/${projectData.name_with_namespace}/edit/${branchId}`;
testAction(
openBranch,
branchId,
mockedState,
[],
[{ type: 'goToRoute', payload: expectedPath }],
done,
);
});
});
}); });
}); });
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