Merge branch '57668-create-file-from-url' into 'master'
Resolve "Support creating new file from URL in the Web IDE" Closes #57668 See merge request gitlab-org/gitlab-ce!26622
This commit is contained in:
commit
9fb1dfa870
8 changed files with 271 additions and 17 deletions
|
@ -147,6 +147,11 @@ export const openBranch = ({ dispatch, state }, { projectId, branchId, basePath
|
|||
|
||||
if (treeEntry) {
|
||||
dispatch('handleTreeEntryAction', treeEntry);
|
||||
} else {
|
||||
dispatch('createTempEntry', {
|
||||
name: path,
|
||||
type: 'blob',
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as types from '../mutation_types';
|
||||
import { sortTree } from '../utils';
|
||||
import { sortTree, mergeTrees } from '../utils';
|
||||
|
||||
export default {
|
||||
[types.TOGGLE_TREE_OPEN](state, path) {
|
||||
|
@ -23,9 +23,15 @@ export default {
|
|||
});
|
||||
},
|
||||
[types.SET_DIRECTORY_DATA](state, { data, treePath }) {
|
||||
Object.assign(state.trees[treePath], {
|
||||
tree: data,
|
||||
});
|
||||
const selectedTree = state.trees[treePath];
|
||||
|
||||
// If we opened files while loading the tree, we need to merge them
|
||||
// Otherwise, simply overwrite the tree
|
||||
const tree = !selectedTree.tree.length
|
||||
? data
|
||||
: selectedTree.loading && mergeTrees(selectedTree.tree, data);
|
||||
|
||||
Object.assign(selectedTree, { tree });
|
||||
},
|
||||
[types.SET_LAST_COMMIT_URL](state, { tree = state, url }) {
|
||||
Object.assign(tree, {
|
||||
|
|
|
@ -170,3 +170,31 @@ export const filePathMatches = (filePath, path) => filePath.indexOf(`${path}/`)
|
|||
|
||||
export const getChangesCountForFiles = (files, path) =>
|
||||
files.filter(f => filePathMatches(f.path, path)).length;
|
||||
|
||||
export const mergeTrees = (fromTree, toTree) => {
|
||||
if (!fromTree || !fromTree.length) {
|
||||
return toTree;
|
||||
}
|
||||
|
||||
const recurseTree = (n, t) => {
|
||||
if (!n) {
|
||||
return t;
|
||||
}
|
||||
const existingTreeNode = t.find(el => el.path === n.path);
|
||||
|
||||
if (existingTreeNode && n.tree.length > 0) {
|
||||
existingTreeNode.opened = true;
|
||||
recurseTree(n.tree[0], existingTreeNode.tree);
|
||||
} else if (!existingTreeNode) {
|
||||
const sorted = sortTree(t.concat(n));
|
||||
t.splice(0, t.length + 1, ...sorted);
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
||||
for (let i = 0, l = fromTree.length; i < l; i += 1) {
|
||||
recurseTree(fromTree[i], toTree);
|
||||
}
|
||||
|
||||
return toTree;
|
||||
};
|
||||
|
|
5
changelogs/unreleased/57668-create-file-from-url.yml
Normal file
5
changelogs/unreleased/57668-create-file-from-url.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Implemented support for creation of new files from URL in Web IDE
|
||||
merge_request: 26622
|
||||
author:
|
||||
type: added
|
|
@ -279,5 +279,22 @@ describe('IDE store project actions', () => {
|
|||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
|
||||
it('creates a new file supplied via URL if the file does not exist yet', done => {
|
||||
openBranch(store, { ...branch, basePath: 'not-existent.md' })
|
||||
.then(() => {
|
||||
expect(store.dispatch).not.toHaveBeenCalledWith(
|
||||
'handleTreeEntryAction',
|
||||
jasmine.anything(),
|
||||
);
|
||||
|
||||
expect(store.dispatch).toHaveBeenCalledWith('createTempEntry', {
|
||||
name: 'not-existent.md',
|
||||
type: 'blob',
|
||||
});
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import testAction from 'spec/helpers/vuex_action_helper';
|
||||
import { showTreeEntry, getFiles } from '~/ide/stores/actions/tree';
|
||||
import { showTreeEntry, getFiles, setDirectoryData } from '~/ide/stores/actions/tree';
|
||||
import * as types from '~/ide/stores/mutation_types';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import store from '~/ide/stores';
|
||||
|
@ -206,4 +206,35 @@ describe('Multi-file store tree actions', () => {
|
|||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setDirectoryData', () => {
|
||||
it('sets tree correctly if there are no opened files yet', done => {
|
||||
const treeFile = file({ name: 'README.md' });
|
||||
store.state.trees['abcproject/master'] = {};
|
||||
|
||||
testAction(
|
||||
setDirectoryData,
|
||||
{ projectId: 'abcproject', branchId: 'master', treeList: [treeFile] },
|
||||
store.state,
|
||||
[
|
||||
{
|
||||
type: types.SET_DIRECTORY_DATA,
|
||||
payload: {
|
||||
treePath: 'abcproject/master',
|
||||
data: [treeFile],
|
||||
},
|
||||
},
|
||||
{
|
||||
type: types.TOGGLE_LOADING,
|
||||
payload: {
|
||||
entry: {},
|
||||
forceValue: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
[],
|
||||
done,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -26,17 +26,11 @@ describe('Multi-file store tree mutations', () => {
|
|||
});
|
||||
|
||||
describe('SET_DIRECTORY_DATA', () => {
|
||||
const data = [
|
||||
{
|
||||
name: 'tree',
|
||||
},
|
||||
{
|
||||
name: 'submodule',
|
||||
},
|
||||
{
|
||||
name: 'blob',
|
||||
},
|
||||
];
|
||||
let data;
|
||||
|
||||
beforeEach(() => {
|
||||
data = [file('tree'), file('foo'), file('blob')];
|
||||
});
|
||||
|
||||
it('adds directory data', () => {
|
||||
localState.trees['project/master'] = {
|
||||
|
@ -52,7 +46,7 @@ describe('Multi-file store tree mutations', () => {
|
|||
|
||||
expect(tree.tree.length).toBe(3);
|
||||
expect(tree.tree[0].name).toBe('tree');
|
||||
expect(tree.tree[1].name).toBe('submodule');
|
||||
expect(tree.tree[1].name).toBe('foo');
|
||||
expect(tree.tree[2].name).toBe('blob');
|
||||
});
|
||||
|
||||
|
@ -65,6 +59,49 @@ describe('Multi-file store tree mutations', () => {
|
|||
|
||||
expect(localState.trees['project/master'].loading).toBe(true);
|
||||
});
|
||||
|
||||
it('does not override tree already in state, but merges the two with correct order', () => {
|
||||
const openedFile = file('new');
|
||||
|
||||
localState.trees['project/master'] = {
|
||||
loading: true,
|
||||
tree: [openedFile],
|
||||
};
|
||||
|
||||
mutations.SET_DIRECTORY_DATA(localState, {
|
||||
data,
|
||||
treePath: 'project/master',
|
||||
});
|
||||
|
||||
const { tree } = localState.trees['project/master'];
|
||||
|
||||
expect(tree.length).toBe(4);
|
||||
expect(tree[0].name).toBe('blob');
|
||||
expect(tree[1].name).toBe('foo');
|
||||
expect(tree[2].name).toBe('new');
|
||||
expect(tree[3].name).toBe('tree');
|
||||
});
|
||||
|
||||
it('returns tree unchanged if the opened file is already in the tree', () => {
|
||||
const openedFile = file('foo');
|
||||
localState.trees['project/master'] = {
|
||||
loading: true,
|
||||
tree: [openedFile],
|
||||
};
|
||||
|
||||
mutations.SET_DIRECTORY_DATA(localState, {
|
||||
data,
|
||||
treePath: 'project/master',
|
||||
});
|
||||
|
||||
const { tree } = localState.trees['project/master'];
|
||||
|
||||
expect(tree.length).toBe(3);
|
||||
|
||||
expect(tree[0].name).toBe('tree');
|
||||
expect(tree[1].name).toBe('foo');
|
||||
expect(tree[2].name).toBe('blob');
|
||||
});
|
||||
});
|
||||
|
||||
describe('REMOVE_ALL_CHANGES_FILES', () => {
|
||||
|
|
|
@ -235,4 +235,129 @@ describe('Multi-file store utils', () => {
|
|||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeTrees', () => {
|
||||
let fromTree;
|
||||
let toTree;
|
||||
|
||||
beforeEach(() => {
|
||||
fromTree = [file('foo')];
|
||||
toTree = [file('bar')];
|
||||
});
|
||||
|
||||
it('merges simple trees with sorting the result', () => {
|
||||
toTree = [file('beta'), file('alpha'), file('gamma')];
|
||||
const res = utils.mergeTrees(fromTree, toTree);
|
||||
|
||||
expect(res.length).toEqual(4);
|
||||
expect(res[0].name).toEqual('alpha');
|
||||
expect(res[1].name).toEqual('beta');
|
||||
expect(res[2].name).toEqual('foo');
|
||||
expect(res[3].name).toEqual('gamma');
|
||||
expect(res[2]).toBe(fromTree[0]);
|
||||
});
|
||||
|
||||
it('handles edge cases', () => {
|
||||
expect(utils.mergeTrees({}, []).length).toEqual(0);
|
||||
|
||||
let res = utils.mergeTrees({}, toTree);
|
||||
|
||||
expect(res.length).toEqual(1);
|
||||
expect(res[0].name).toEqual('bar');
|
||||
|
||||
res = utils.mergeTrees(fromTree, []);
|
||||
|
||||
expect(res.length).toEqual(1);
|
||||
expect(res[0].name).toEqual('foo');
|
||||
expect(res[0]).toBe(fromTree[0]);
|
||||
});
|
||||
|
||||
it('merges simple trees without producing duplicates', () => {
|
||||
toTree.push(file('foo'));
|
||||
|
||||
const res = utils.mergeTrees(fromTree, toTree);
|
||||
|
||||
expect(res.length).toEqual(2);
|
||||
expect(res[0].name).toEqual('bar');
|
||||
expect(res[1].name).toEqual('foo');
|
||||
expect(res[1]).not.toBe(fromTree[0]);
|
||||
});
|
||||
|
||||
it('merges nested tree into the main one without duplicates', () => {
|
||||
fromTree[0].tree.push({
|
||||
...file('alpha'),
|
||||
path: 'foo/alpha',
|
||||
tree: [
|
||||
{
|
||||
...file('beta.md'),
|
||||
path: 'foo/alpha/beta.md',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
toTree.push({
|
||||
...file('foo'),
|
||||
tree: [
|
||||
{
|
||||
...file('alpha'),
|
||||
path: 'foo/alpha',
|
||||
tree: [
|
||||
{
|
||||
...file('gamma.md'),
|
||||
path: 'foo/alpha/gamma.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = utils.mergeTrees(fromTree, toTree);
|
||||
|
||||
expect(res.length).toEqual(2);
|
||||
expect(res[1].name).toEqual('foo');
|
||||
|
||||
const finalBranch = res[1].tree[0].tree;
|
||||
|
||||
expect(finalBranch.length).toEqual(2);
|
||||
expect(finalBranch[0].name).toEqual('beta.md');
|
||||
expect(finalBranch[1].name).toEqual('gamma.md');
|
||||
});
|
||||
|
||||
it('marks correct folders as opened as the parsing goes on', () => {
|
||||
fromTree[0].tree.push({
|
||||
...file('alpha'),
|
||||
path: 'foo/alpha',
|
||||
tree: [
|
||||
{
|
||||
...file('beta.md'),
|
||||
path: 'foo/alpha/beta.md',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
toTree.push({
|
||||
...file('foo'),
|
||||
tree: [
|
||||
{
|
||||
...file('alpha'),
|
||||
path: 'foo/alpha',
|
||||
tree: [
|
||||
{
|
||||
...file('gamma.md'),
|
||||
path: 'foo/alpha/gamma.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const res = utils.mergeTrees(fromTree, toTree);
|
||||
|
||||
expect(res[1].name).toEqual('foo');
|
||||
expect(res[1].opened).toEqual(true);
|
||||
|
||||
expect(res[1].tree[0].name).toEqual('alpha');
|
||||
expect(res[1].tree[0].opened).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue