Commit 1684c86f authored by Phil Hughes's avatar Phil Hughes

Merge branch 'tz-ide-load-full-file-structure' into 'master'

IDE: Load full Files structure through API

See merge request gitlab-org/gitlab-ee!4859
parents ce65cd37 72d0efc9
...@@ -46,19 +46,35 @@ ...@@ -46,19 +46,35 @@
background: $white-normal; background: $white-normal;
} }
.repo-file-name { .ide-file-name {
flex: 1;
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
svg {
vertical-align: middle;
margin-right: 2px;
}
.loading-container {
margin-right: 4px;
display: inline-block;
}
} }
.repo-new-btn { .ide-file-changed-icon {
margin-left: auto;
}
.ide-new-btn {
display: none; display: none;
margin-top: -4px; margin-top: -4px;
margin-bottom: -4px; margin-bottom: -4px;
margin-right: -8px;
} }
&:hover { &:hover {
.repo-new-btn { .ide-new-btn {
display: block; display: block;
} }
} }
...@@ -81,10 +97,10 @@ ...@@ -81,10 +97,10 @@
} }
} }
.multi-file-table-name, .file-name,
.multi-file-table-col-commit-message { .file-col-commit-message {
display: flex;
overflow: visible; overflow: visible;
max-width: 0;
padding: 6px 12px; padding: 6px 12px;
} }
...@@ -101,21 +117,6 @@ ...@@ -101,21 +117,6 @@
} }
} }
table.table tr td.multi-file-table-name {
width: 350px;
padding: 6px 12px;
svg {
vertical-align: middle;
margin-right: 2px;
}
.loading-container {
margin-right: 4px;
display: inline-block;
}
}
.multi-file-table-col-commit-message { .multi-file-table-col-commit-message {
white-space: nowrap; white-space: nowrap;
width: 50%; width: 50%;
...@@ -558,7 +559,7 @@ table.table tr td.multi-file-table-name { ...@@ -558,7 +559,7 @@ table.table tr td.multi-file-table-name {
justify-content: center; justify-content: center;
} }
.repo-new-btn { .ide-new-btn {
.dropdown-toggle svg { .dropdown-toggle svg {
margin-top: -2px; margin-top: -2px;
margin-bottom: 2px; margin-bottom: 2px;
......
...@@ -26,6 +26,6 @@ ...@@ -26,6 +26,6 @@
<icon <icon
:name="changedIcon" :name="changedIcon"
:size="12" :size="12"
:css-classes="`multi-file-changed-icon ${changedIconClass}`" :css-classes="`ide-file-changed-icon ${changedIconClass}`"
/> />
</template> </template>
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import repoPreviousDirectory from './repo_prev_directory.vue';
import repoFile from './repo_file.vue'; import repoFile from './repo_file.vue';
import { treeList } from '../stores/utils';
export default { export default {
components: { components: {
repoPreviousDirectory,
repoFile, repoFile,
skeletonLoadingContainer, skeletonLoadingContainer,
}, },
...@@ -20,55 +17,40 @@ export default { ...@@ -20,55 +17,40 @@ export default {
computed: { computed: {
...mapState([ ...mapState([
'trees', 'trees',
'isRoot',
]), ]),
...mapState({ ...mapState({
projectName(state) { projectName(state) {
return state.project.name; return state.project.name;
}, },
}), }),
fetchedList() { selctedTree() {
return treeList(this.$store.state, this.treeId); return this.trees[this.treeId].tree;
},
hasPreviousDirectory() {
return !this.isRoot && this.fetchedList.length;
}, },
showLoading() { showLoading() {
if (this.trees[this.treeId]) { return !this.trees[this.treeId] || this.trees[this.treeId].loading;
return this.trees[this.treeId].loading;
}
return true;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div> <div
<div class="ide-file-list"> class="ide-file-list"
<table class="table"> v-if="treeId"
<tbody >
v-if="treeId" <template v-if="showLoading">
> <div
<repo-previous-directory class="multi-file-loading-container"
v-if="hasPreviousDirectory" v-for="n in 3"
/> :key="n"
<template v-if="showLoading"> >
<div <skeleton-loading-container />
class="multi-file-loading-container" </div>
v-for="n in 3" </template>
:key="n" <repo-file
> v-for="file in selctedTree"
<skeleton-loading-container /> :key="file.key"
</div> :file="file"
</template> />
<repo-file
v-for="file in fetchedList"
:key="file.key"
:file="file"
/>
</tbody>
</table>
</div>
</div> </div>
</template> </template>
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
</script> </script>
<template> <template>
<div class="repo-new-btn pull-right"> <div class="ide-new-btn">
<div <div
class="dropdown" class="dropdown"
:class="{ :class="{
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue'; // eslint-disable-line import/first import changedFileIcon from 'ee/ide/components/changed_file_icon.vue'; // eslint-disable-line import/first
export default { export default {
name: 'RepoFile',
components: { components: {
skeletonLoadingContainer, skeletonLoadingContainer,
newDropdown, newDropdown,
...@@ -51,9 +52,6 @@ ...@@ -51,9 +52,6 @@
shortId() { shortId() {
return this.file.id.substr(0, 8); return this.file.id.substr(0, 8);
}, },
submoduleColSpan() {
return !this.leftPanelCollapsed && this.isSubmodule ? 3 : 1;
},
fileClass() { fileClass() {
if (this.file.type === 'blob') { if (this.file.type === 'blob') {
if (this.file.active) { if (this.file.active) {
...@@ -87,82 +85,62 @@ ...@@ -87,82 +85,62 @@
</script> </script>
<template> <template>
<tr <div>
class="file" <div
:class="fileClass" class="file"
> :class="fileClass"
<td
class="multi-file-table-name"
:colspan="submoduleColSpan"
@click="clickFile(file)"
> >
<a <div
class="repo-file-name str-truncated" class="file-name"
@click="clickFile(file)"
> >
<file-icon
:file-name="file.name"
:loading="file.loading"
:folder="file.type === 'tree'"
:opened="file.opened"
:style="levelIndentation"
:size="16"
/>
{{ file.name }}
<file-status-icon :file="file" />
</a>
<new-dropdown
v-if="isTree"
:project-id="file.projectId"
:branch="file.branchId"
:path="file.path"
:parent="file"
/>
<changed-file-icon
v-if="file.changed || file.tempFile"
:file="file"
class="prepend-top-5 pull-right"
/>
<template v-if="isSubmodule && file.id">
@
<span class="commit-sha">
<a
@click.stop
:href="file.tree_url"
>
{{ shortId }}
</a>
</span>
</template>
</td>
<template v-if="showExtraColumns && !isSubmodule">
<td class="multi-file-table-col-commit-message hidden-sm hidden-xs">
<a <a
v-if="file.lastCommit.message" class="ide-file-name str-truncated"
@click.stop
:href="file.lastCommit.url"
> >
{{ file.lastCommit.message }} <file-icon
:file-name="file.name"
:loading="file.loading"
:folder="file.type === 'tree'"
:opened="file.opened"
:style="levelIndentation"
:size="16"
/>
{{ file.name }}
<file-status-icon :file="file" />
</a> </a>
<skeleton-loading-container <new-dropdown
v-else v-if="isTree"
:small="true" :project-id="file.projectId"
:branch="file.branchId"
:path="file.path"
:parent="file"
/> />
</td> <changed-file-icon
:file="file"
<td class="commit-update hidden-xs text-right"> v-if="file.changed || file.tempFile"
<span class="prepend-top-5"
v-if="file.lastCommit.updatedAt"
:title="tooltipTitle(file.lastCommit.updatedAt)"
>
{{ timeFormated(file.lastCommit.updatedAt) }}
</span>
<skeleton-loading-container
v-else
class="animation-container-right"
:small="true"
/> />
</td> <template v-if="isSubmodule && file.id">
@
<span class="commit-sha">
<a
@click.stop
:href="file.tree_url"
>
{{ shortId }}
</a>
</span>
</template>
</div>
</div>
<template
v-if="file.opened"
>
<repo-file
v-for="childFile in file.tree"
:key="childFile.key"
:file="childFile"
/>
</template> </template>
</tr> </div>
</template> </template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
computed: {
...mapState([
'parentTreeUrl',
'leftPanelCollapsed',
]),
colSpanCondition() {
return this.leftPanelCollapsed ? undefined : 3;
},
},
methods: {
...mapActions([
'getTreeData',
]),
},
};
</script>
<template>
<tr class="file prev-directory">
<td
:colspan="colSpanCondition"
class="table-cell"
@click.prevent="getTreeData({ endpoint: parentTreeUrl })"
>
<a :href="parentTreeUrl">...</a>
</td>
</tr>
</template>
...@@ -70,10 +70,9 @@ router.beforeEach((to, from, next) => { ...@@ -70,10 +70,9 @@ router.beforeEach((to, from, next) => {
branchId: to.params.branch, branchId: to.params.branch,
}); });
store.dispatch('getTreeData', { store.dispatch('getFiles', {
projectId: fullProjectId, projectId: fullProjectId,
branch: to.params.branch, branchId: to.params.branch,
endpoint: `/tree/${to.params.branch}`,
}) })
.then(() => { .then(() => {
if (to.params[0]) { if (to.params[0]) {
......
...@@ -44,4 +44,12 @@ export default { ...@@ -44,4 +44,12 @@ export default {
}, },
}); });
}, },
getFiles(projectUrl, branchId) {
const url = `${projectUrl}/files/${branchId}`;
return Vue.http.get(url, {
params: {
format: 'json',
},
});
},
}; };
...@@ -49,7 +49,7 @@ export const setFileActive = ({ commit, state, getters, dispatch }, file) => { ...@@ -49,7 +49,7 @@ export const setFileActive = ({ commit, state, getters, dispatch }, file) => {
}; };
export const getFileData = ({ state, commit, dispatch }, file) => { export const getFileData = ({ state, commit, dispatch }, file) => {
commit(types.TOGGLE_LOADING, file); commit(types.TOGGLE_LOADING, { entry: file });
service.getFileData(file.url) service.getFileData(file.url)
.then((res) => { .then((res) => {
...@@ -63,10 +63,10 @@ export const getFileData = ({ state, commit, dispatch }, file) => { ...@@ -63,10 +63,10 @@ export const getFileData = ({ state, commit, dispatch }, file) => {
commit(types.SET_FILE_DATA, { data, file }); commit(types.SET_FILE_DATA, { data, file });
commit(types.TOGGLE_FILE_OPEN, file); commit(types.TOGGLE_FILE_OPEN, file);
dispatch('setFileActive', file); dispatch('setFileActive', file);
commit(types.TOGGLE_LOADING, file); commit(types.TOGGLE_LOADING, { entry: file });
}) })
.catch(() => { .catch(() => {
commit(types.TOGGLE_LOADING, file); commit(types.TOGGLE_LOADING, { entry: file });
flash('Error loading file data. Please try again.', 'alert', document, null, false, true); flash('Error loading file data. Please try again.', 'alert', document, null, false, true);
}); });
}; };
......
...@@ -8,11 +8,11 @@ export const getProjectData = ( ...@@ -8,11 +8,11 @@ export const getProjectData = (
{ namespace, projectId, force = false } = {}, { namespace, projectId, force = false } = {},
) => new Promise((resolve, reject) => { ) => new Promise((resolve, reject) => {
if (!state.projects[`${namespace}/${projectId}`] || force) { if (!state.projects[`${namespace}/${projectId}`] || force) {
commit(types.TOGGLE_LOADING, state); commit(types.TOGGLE_LOADING, { entry: state });
service.getProjectData(namespace, projectId) service.getProjectData(namespace, projectId)
.then(res => res.data) .then(res => res.data)
.then((data) => { .then((data) => {
commit(types.TOGGLE_LOADING, state); commit(types.TOGGLE_LOADING, { entry: state });
commit(types.SET_PROJECT, { projectPath: `${namespace}/${projectId}`, project: data }); commit(types.SET_PROJECT, { projectPath: `${namespace}/${projectId}`, project: data });
if (!state.currentProjectId) commit(types.SET_CURRENT_PROJECT, `${namespace}/${projectId}`); if (!state.currentProjectId) commit(types.SET_CURRENT_PROJECT, `${namespace}/${projectId}`);
resolve(data); resolve(data);
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
findEntry, findEntry,
createTemp, createTemp,
createOrMergeEntry, createOrMergeEntry,
sortTree,
} from '../utils'; } from '../utils';
export const getTreeData = ( export const getTreeData = (
...@@ -19,7 +20,7 @@ export const getTreeData = ( ...@@ -19,7 +20,7 @@ export const getTreeData = (
if (!tree && state.trees[`${projectId}/${branch}`] && !force) { if (!tree && state.trees[`${projectId}/${branch}`] && !force) {
resolve(); resolve();
} else { } else {
if (tree) commit(types.TOGGLE_LOADING, tree); if (tree) commit(types.TOGGLE_LOADING, { entry: tree });
const selectedProject = state.projects[projectId]; const selectedProject = state.projects[projectId];
// We are merging the web_url that we got on the project info with the endpoint // We are merging the web_url that we got on the project info with the endpoint
// we got on the tree entry, as both contain the projectId, we replace it in the tree endpoint // we got on the tree entry, as both contain the projectId, we replace it in the tree endpoint
...@@ -34,16 +35,12 @@ export const getTreeData = ( ...@@ -34,16 +35,12 @@ export const getTreeData = (
return res.json(); return res.json();
}) })
.then((data) => { .then((data) => {
if (!state.isInitialRoot) {
commit(types.SET_ROOT, data.path === '/');
}
dispatch('updateDirectoryData', { data, tree, projectId, branch, clearTree: false }); dispatch('updateDirectoryData', { data, tree, projectId, branch, clearTree: false });
const selectedTree = tree || state.trees[`${projectId}/${branch}`]; const selectedTree = tree || state.trees[`${projectId}/${branch}`];
commit(types.SET_PARENT_TREE_URL, data.parent_tree_url); commit(types.SET_PARENT_TREE_URL, data.parent_tree_url);
commit(types.SET_LAST_COMMIT_URL, { tree: selectedTree, url: data.last_commit_path }); commit(types.SET_LAST_COMMIT_URL, { tree: selectedTree, url: data.last_commit_path });
if (tree) commit(types.TOGGLE_LOADING, selectedTree); if (tree) commit(types.TOGGLE_LOADING, { entry: selectedTree });
const prevLastCommitPath = selectedTree.lastCommitPath; const prevLastCommitPath = selectedTree.lastCommitPath;
if (prevLastCommitPath !== null) { if (prevLastCommitPath !== null) {
...@@ -53,7 +50,7 @@ export const getTreeData = ( ...@@ -53,7 +50,7 @@ export const getTreeData = (
}) })
.catch((e) => { .catch((e) => {
flash('Error loading tree data. Please try again.', 'alert', document, null, false, true); flash('Error loading tree data. Please try again.', 'alert', document, null, false, true);
if (tree) commit(types.TOGGLE_LOADING, tree); if (tree) commit(types.TOGGLE_LOADING, { entry: tree });
reject(e); reject(e);
}); });
} else { } else {
...@@ -62,16 +59,7 @@ export const getTreeData = ( ...@@ -62,16 +59,7 @@ export const getTreeData = (
} }
}); });
export const toggleTreeOpen = ({ commit, dispatch }, { endpoint, tree }) => { export const toggleTreeOpen = ({ commit, dispatch }, { tree }) => {
if (tree.opened) {
// send empty data to clear the tree
const data = { trees: [], blobs: [], submodules: [] };
dispatch('updateDirectoryData', { data, tree, projectId: tree.projectId, branchId: tree.branchId });
} else {
dispatch('getTreeData', { endpoint, tree, projectId: tree.projectId, branch: tree.branchId });
}
commit(types.TOGGLE_TREE_OPEN, tree); commit(types.TOGGLE_TREE_OPEN, tree);
}; };
...@@ -82,7 +70,7 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => { ...@@ -82,7 +70,7 @@ export const handleTreeEntryAction = ({ commit, dispatch }, row) => {
tree: row, tree: row,
}); });
} else if (row.type === 'submodule') { } else if (row.type === 'submodule') {
commit(types.TOGGLE_LOADING, row); commit(types.TOGGLE_LOADING, { entry: row });
visitUrl(row.url); visitUrl(row.url);
} else if (row.type === 'blob' && (row.opened || row.changed)) { } else if (row.type === 'blob' && (row.opened || row.changed)) {
if (row.changed && !row.opened) { if (row.changed && !row.opened) {
...@@ -198,3 +186,95 @@ export const updateDirectoryData = ( ...@@ -198,3 +186,95 @@ export const updateDirectoryData = (
commit(types.SET_DIRECTORY_DATA, { tree: selectedTree, data: formattedData }); commit(types.SET_DIRECTORY_DATA, { tree: selectedTree, data: formattedData });
}; };
export const getFiles = (
{ state, commit, dispatch },
{ projectId, branchId } = {},
) => new Promise((resolve, reject) => {
if (!state.trees[`${projectId}/${branchId}`]) {
const selectedProject = state.projects[projectId];
commit(types.CREATE_TREE, { treePath: `${projectId}/${branchId}` });
service
.getFiles(selectedProject.web_url, branchId)
.then(res => res.json())
.then((data) => {
const newTree = data.reduce((outputArray, file) => {
const pathSplit = file.split('/');
const blobName = pathSplit.pop();
let selectedFolderTree;
let foundFolder = null;
let fullPath = '';
if (pathSplit.length > 0) {
const newBaseFolders = pathSplit.reduce((newFolders, folder, currentIndex) => {
fullPath += `/${folder}`;
foundFolder = findEntry(selectedFolderTree || outputArray, 'tree', fullPath, 'path');
if (!foundFolder) {
foundFolder = createOrMergeEntry({
projectId,
branchId,
entry: {
id: fullPath,
name: folder,
path: fullPath,
url: `/${projectId}/tree/${branchId}/${fullPath}`,
},
level: currentIndex,
type: 'tree',
parentTreeUrl: '',
state,
});
if (selectedFolderTree) {
selectedFolderTree.push(foundFolder);
} else {
newFolders.push(foundFolder);
}
}
selectedFolderTree = foundFolder.tree;
return newFolders;
}, []);
if (newBaseFolders.length) outputArray.push(newBaseFolders[0]);
}
// Add file
const blobEntry = createOrMergeEntry({
projectId,
branchId,
entry: {
id: file,
name: blobName,
path: file,
url: `/${projectId}/blob/${branchId}/${file}`,
},
level: foundFolder ? (foundFolder.level + 1) : 0,
type: 'blob',
parentTreeUrl: foundFolder ? foundFolder.url : '',
state,
});
if (selectedFolderTree) {
selectedFolderTree.push(blobEntry);
} else {
outputArray.push(blobEntry);
}
return outputArray;
}, []);
const selectedTree = state.trees[`${projectId}/${branchId}`];
commit(types.SET_DIRECTORY_DATA, { tree: selectedTree, data: sortTree(newTree) });
commit(types.TOGGLE_LOADING, { entry: selectedTree, forceValue: false });
resolve();
})
.catch((e) => {
flash('Error loading tree data. Please try again.', 'alert', document, null, false, true);
reject(e);
});
} else {
resolve();
}
});
export const SET_INITIAL_DATA = 'SET_INITIAL_DATA'; export const SET_INITIAL_DATA = 'SET_INITIAL_DATA';
export const TOGGLE_LOADING = 'TOGGLE_LOADING'; export const TOGGLE_LOADING = 'TOGGLE_LOADING';
export const SET_PARENT_TREE_URL = 'SET_PARENT_TREE_URL'; export const SET_PARENT_TREE_URL = 'SET_PARENT_TREE_URL';
export const SET_ROOT = 'SET_ROOT';
export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA'; export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA';
export const SET_LAST_COMMIT_MSG = 'SET_LAST_COMMIT_MSG'; export const SET_LAST_COMMIT_MSG = 'SET_LAST_COMMIT_MSG';
export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED'; export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED';
......
...@@ -18,9 +18,9 @@ export default { ...@@ -18,9 +18,9 @@ export default {
currentBlobView: 'repo-editor', currentBlobView: 'repo-editor',
}); });
}, },
[types.TOGGLE_LOADING](state, entry) { [types.TOGGLE_LOADING](state, { entry, forceValue = undefined }) {
Object.assign(entry, { Object.assign(entry, {
loading: !entry.loading, loading: forceValue !== undefined ? forceValue : !entry.loading,
}); });
}, },
[types.TOGGLE_EDIT_MODE](state) { [types.TOGGLE_EDIT_MODE](state) {
...@@ -28,12 +28,6 @@ export default { ...@@ -28,12 +28,6 @@ export default {
editMode: !state.editMode, editMode: !state.editMode,
}); });
}, },
[types.SET_ROOT](state, isRoot) {
Object.assign(state, {
isRoot,
isInitialRoot: isRoot,
});
},
[types.SET_LEFT_PANEL_COLLAPSED](state, collapsed) { [types.SET_LEFT_PANEL_COLLAPSED](state, collapsed) {
Object.assign(state, { Object.assign(state, {
leftPanelCollapsed: collapsed, leftPanelCollapsed: collapsed,
......
...@@ -24,12 +24,12 @@ export default { ...@@ -24,12 +24,12 @@ export default {
}, },
[types.SET_FILE_DATA](state, { data, file }) { [types.SET_FILE_DATA](state, { data, file }) {
Object.assign(file, { Object.assign(file, {
id: data.id,
blamePath: data.blame_path, blamePath: data.blame_path,
commitsPath: data.commits_path, commitsPath: data.commits_path,
permalink: data.permalink, permalink: data.permalink,
rawPath: data.raw_path, rawPath: data.raw_path,
binary: data.binary, binary: data.binary,
html: data.html,
renderError: data.render_error, renderError: data.render_error,
}); });
}, },
......
...@@ -11,6 +11,7 @@ export default { ...@@ -11,6 +11,7 @@ export default {
trees: Object.assign({}, state.trees, { trees: Object.assign({}, state.trees, {
[treePath]: { [treePath]: {
tree: [], tree: [],
loading: true,
}, },
}), }),
}); });
......
...@@ -6,7 +6,6 @@ export default () => ({ ...@@ -6,7 +6,6 @@ export default () => ({
changedFiles: [], changedFiles: [],
editMode: true, editMode: true,
endpoints: {}, endpoints: {},
isRoot: false,
isInitialRoot: false, isInitialRoot: false,
lastCommitMsg: '', lastCommitMsg: '',
lastCommitPath: '', lastCommitPath: '',
......
...@@ -202,3 +202,23 @@ export const createCommitPayload = (branch, newBranch, state, rootState) => ({ ...@@ -202,3 +202,23 @@ export const createCommitPayload = (branch, newBranch, state, rootState) => ({
export const createNewMergeRequestUrl = (projectUrl, source, target) => export const createNewMergeRequestUrl = (projectUrl, source, target) =>
`${projectUrl}/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}`; `${projectUrl}/merge_requests/new?merge_request[source_branch]=${source}&merge_request[target_branch]=${target}`;
const sortTreesByTypeAndName = (a, b) => {
if (a.type === 'tree' && b.type === 'blob') {
return -1;
} else if (a.type === 'blob' && b.type === 'tree') {
return 1;
}
if (a.name.toLowerCase() < b.name.toLowerCase()) return -1;
if (a.name.toLowerCase() > b.name.toLowerCase()) return 1;
return 0;
};
export const sortTree = (sortedTree) => {
sortedTree.forEach((el) => {
Object.assign(el, {
tree: el && el.tree ? sortTree(el.tree) : [],
});
});
return sortedTree.sort(sortTreesByTypeAndName);
};
...@@ -17,7 +17,6 @@ describe('IdeRepoTree', () => { ...@@ -17,7 +17,6 @@ describe('IdeRepoTree', () => {
}); });
vm.$store.state.currentBranch = 'master'; vm.$store.state.currentBranch = 'master';
vm.$store.state.isRoot = true;
vm.$store.state.trees['abcproject/mybranch'] = { vm.$store.state.trees['abcproject/mybranch'] = {
tree: [file()], tree: [file()],
}; };
...@@ -32,16 +31,17 @@ describe('IdeRepoTree', () => { ...@@ -32,16 +31,17 @@ describe('IdeRepoTree', () => {
}); });
it('renders a sidebar', () => { it('renders a sidebar', () => {
const tbody = vm.$el.querySelector('tbody');
expect(vm.$el.classList.contains('sidebar-mini')).toBeFalsy(); expect(vm.$el.classList.contains('sidebar-mini')).toBeFalsy();
expect(tbody.querySelector('.repo-file-options')).toBeFalsy(); expect(vm.$el.querySelector('.repo-file-options')).toBeFalsy();
expect(tbody.querySelector('.prev-directory')).toBeFalsy(); expect(vm.$el.querySelector('.loading-file')).toBeFalsy();
expect(tbody.querySelector('.loading-file')).toBeFalsy(); expect(vm.$el.querySelector('.file')).toBeTruthy();
expect(tbody.querySelector('.file')).toBeTruthy();
}); });
it('renders 3 loading files if tree is loading', (done) => { it('renders 3 loading files if tree is loading', (done) => {
vm.$store.state.trees['123'] = {
tree: [],
loading: true,
};
vm.treeId = '123'; vm.treeId = '123';
Vue.nextTick(() => { Vue.nextTick(() => {
...@@ -50,14 +50,4 @@ describe('IdeRepoTree', () => { ...@@ -50,14 +50,4 @@ describe('IdeRepoTree', () => {
done(); done();
}); });
}); });
it('renders a prev directory if is not root', (done) => {
vm.$store.state.isRoot = false;
Vue.nextTick(() => {
expect(vm.$el.querySelector('tbody .prev-directory')).toBeTruthy();
done();
});
});
}); });
...@@ -31,7 +31,7 @@ describe('RepoFile', () => { ...@@ -31,7 +31,7 @@ describe('RepoFile', () => {
spyOn(vm, 'timeFormated').and.returnValue(updated); spyOn(vm, 'timeFormated').and.returnValue(updated);
vm.$mount(); vm.$mount();
const name = vm.$el.querySelector('.repo-file-name'); const name = vm.$el.querySelector('.ide-file-name');
expect(name.href).toMatch(''); expect(name.href).toMatch('');
expect(name.textContent.trim()).toEqual(vm.file.name); expect(name.textContent.trim()).toEqual(vm.file.name);
...@@ -66,7 +66,7 @@ describe('RepoFile', () => { ...@@ -66,7 +66,7 @@ describe('RepoFile', () => {
spyOn(vm, 'clickFile'); spyOn(vm, 'clickFile');
vm.$el.querySelector('td').click(); vm.$el.querySelector('.file-name').click();
expect(vm.clickFile).toHaveBeenCalledWith(vm.file); expect(vm.clickFile).toHaveBeenCalledWith(vm.file);
}); });
...@@ -90,10 +90,6 @@ describe('RepoFile', () => { ...@@ -90,10 +90,6 @@ describe('RepoFile', () => {
it('renders submodule short ID', () => { it('renders submodule short ID', () => {
expect(vm.$el.querySelector('.commit-sha').textContent.trim()).toBe('12345678'); expect(vm.$el.querySelector('.commit-sha').textContent.trim()).toBe('12345678');
}); });
it('renders ID next to submodule name', () => {
expect(vm.$el.querySelector('td').textContent.replace(/\s+/g, ' ')).toContain('submodule name @ 12345678');
});
}); });
describe('locked file', () => { describe('locked file', () => {
...@@ -122,7 +118,7 @@ describe('RepoFile', () => { ...@@ -122,7 +118,7 @@ describe('RepoFile', () => {
}); });
it('renders a tooltip', () => { it('renders a tooltip', () => {
expect(vm.$el.querySelector('.repo-file-name span:nth-child(2)').dataset.originalTitle).toContain('Locked by testuser'); expect(vm.$el.querySelector('.ide-file-name span:nth-child(2)').dataset.originalTitle).toContain('Locked by testuser');
}); });
}); });
}); });
import Vue from 'vue';
import store from 'ee/ide/stores';
import repoPrevDirectory from 'ee/ide/components/repo_prev_directory.vue';
import { resetStore } from '../helpers';
describe('RepoPrevDirectory', () => {
let vm;
const parentLink = 'parent';
function createComponent() {
const RepoPrevDirectory = Vue.extend(repoPrevDirectory);
const comp = new RepoPrevDirectory({
store,
});
comp.$store.state.parentTreeUrl = parentLink;
return comp.$mount();
}
beforeEach(() => {
vm = createComponent();
});
afterEach(() => {
vm.$destroy();
resetStore(vm.$store);
});
it('renders a prev dir link', () => {
const link = vm.$el.querySelector('a');
expect(link.href).toMatch(`/${parentLink}`);
expect(link.textContent).toEqual('...');
});
it('clicking row triggers getTreeData', () => {
spyOn(vm, 'getTreeData');
vm.$el.querySelector('td').click();
expect(vm.getTreeData).toHaveBeenCalledWith({ endpoint: parentLink });
});
});
...@@ -11,6 +11,7 @@ describe('Multi-file store tree actions', () => { ...@@ -11,6 +11,7 @@ describe('Multi-file store tree actions', () => {
endpoint: 'rootEndpoint', endpoint: 'rootEndpoint',
projectId: 'abcproject', projectId: 'abcproject',
branch: 'master', branch: 'master',
branchId: 'master',
}; };
beforeEach(() => { beforeEach(() => {
...@@ -113,18 +114,6 @@ describe('Multi-file store tree actions', () => { ...@@ -113,18 +114,6 @@ describe('Multi-file store tree actions', () => {
}).catch(done.fail); }).catch(done.fail);
}); });
it('sets root if not currently at root', (done) => {
store.state.isInitialRoot = false;
store.dispatch('getTreeData', basicCallParameters)
.then(() => {
expect(store.state.isInitialRoot).toBeTruthy();
expect(store.state.isRoot).toBeTruthy();
done();
}).catch(done.fail);
});
it('sets page title', (done) => { it('sets page title', (done) => {
store.dispatch('getTreeData', basicCallParameters) store.dispatch('getTreeData', basicCallParameters)
.then(() => { .then(() => {
...@@ -151,6 +140,42 @@ describe('Multi-file store tree actions', () => { ...@@ -151,6 +140,42 @@ describe('Multi-file store tree actions', () => {
}); });
}); });
describe('getFiles', () => {
beforeEach(() => {
spyOn(service, 'getFiles').and.returnValue(Promise.resolve({
json: () => Promise.resolve([
'file.txt',
'folder/fileinfolder.js',
'folder/subfolder/fileinsubfolder.js',
]),
}));
});
it('calls service getFiles', (done) => {
store.dispatch('getFiles', basicCallParameters)
.then(() => {
expect(service.getFiles).toHaveBeenCalledWith('', 'master');
done();
}).catch(done.fail);
});
it('adds data into tree', (done) => {
store.dispatch('getFiles', basicCallParameters)
.then(() => {
projectTree = store.state.trees['abcproject/master'];
expect(projectTree.tree.length).toBe(2);
expect(projectTree.tree[0].type).toBe('tree');
expect(projectTree.tree[0].tree[1].name).toBe('fileinfolder.js');
expect(projectTree.tree[1].type).toBe('blob');
expect(projectTree.tree[0].tree[0].tree[0].type).toBe('blob');
expect(projectTree.tree[0].tree[0].tree[0].name).toBe('fileinsubfolder.js');
done();
}).catch(done.fail);
});
});
describe('toggleTreeOpen', () => { describe('toggleTreeOpen', () => {
let oldGetTreeData; let oldGetTreeData;
let getTreeDataSpy; let getTreeDataSpy;
...@@ -176,7 +201,6 @@ describe('Multi-file store tree actions', () => { ...@@ -176,7 +201,6 @@ describe('Multi-file store tree actions', () => {
it('toggles the tree open', (done) => { it('toggles the tree open', (done) => {
store.dispatch('toggleTreeOpen', { store.dispatch('toggleTreeOpen', {
endpoint: 'test',
tree, tree,
}).then(() => { }).then(() => {
expect(tree.opened).toBeTruthy(); expect(tree.opened).toBeTruthy();
...@@ -184,38 +208,6 @@ describe('Multi-file store tree actions', () => { ...@@ -184,38 +208,6 @@ describe('Multi-file store tree actions', () => {
done(); done();
}).catch(done.fail); }).catch(done.fail);
}); });
it('calls getTreeData if tree is closed', (done) => {
store.dispatch('toggleTreeOpen', {
endpoint: 'test',
tree,
}).then(() => {
expect(getTreeDataSpy).toHaveBeenCalledWith({
projectId: 'abcproject',
branch: 'master',
endpoint: 'test',
tree,
});
done();
}).catch(done.fail);
});
it('resets entries tree', (done) => {
Object.assign(tree, {
opened: true,
tree: ['a'],
});
store.dispatch('toggleTreeOpen', {
endpoint: 'test',
tree,
}).then(() => {
expect(tree.tree.length).toBe(0);
done();
}).catch(done.fail);
});
}); });
describe('createTempTree', () => { describe('createTempTree', () => {
......
...@@ -49,7 +49,6 @@ describe('Multi-file store file mutations', () => { ...@@ -49,7 +49,6 @@ describe('Multi-file store file mutations', () => {
permalink: 'permalink', permalink: 'permalink',
raw_path: 'raw', raw_path: 'raw',
binary: true, binary: true,
html: 'html',
render_error: 'render_error', render_error: 'render_error',
}, },
file: localFile, file: localFile,
...@@ -60,7 +59,6 @@ describe('Multi-file store file mutations', () => { ...@@ -60,7 +59,6 @@ describe('Multi-file store file mutations', () => {
expect(localFile.permalink).toBe('permalink'); expect(localFile.permalink).toBe('permalink');
expect(localFile.rawPath).toBe('raw'); expect(localFile.rawPath).toBe('raw');
expect(localFile.binary).toBeTruthy(); expect(localFile.binary).toBeTruthy();
expect(localFile.html).toBe('html');
expect(localFile.renderError).toBe('render_error'); expect(localFile.renderError).toBe('render_error');
}); });
}); });
......
...@@ -51,14 +51,24 @@ describe('Multi-file store mutations', () => { ...@@ -51,14 +51,24 @@ describe('Multi-file store mutations', () => {
describe('TOGGLE_LOADING', () => { describe('TOGGLE_LOADING', () => {
it('toggles loading of entry', () => { it('toggles loading of entry', () => {
mutations.TOGGLE_LOADING(localState, entry); mutations.TOGGLE_LOADING(localState, { entry });
expect(entry.loading).toBeTruthy(); expect(entry.loading).toBeTruthy();
mutations.TOGGLE_LOADING(localState, entry); mutations.TOGGLE_LOADING(localState, { entry });
expect(entry.loading).toBeFalsy(); expect(entry.loading).toBeFalsy();
}); });
it('toggles loading of entry and sets specific value', () => {
mutations.TOGGLE_LOADING(localState, { entry });
expect(entry.loading).toBeTruthy();
mutations.TOGGLE_LOADING(localState, { entry, forceValue: true });
expect(entry.loading).toBeTruthy();
});
}); });
describe('TOGGLE_EDIT_MODE', () => { describe('TOGGLE_EDIT_MODE', () => {
...@@ -73,20 +83,6 @@ describe('Multi-file store mutations', () => { ...@@ -73,20 +83,6 @@ describe('Multi-file store mutations', () => {
}); });
}); });
describe('SET_ROOT', () => {
it('sets isRoot & initialRoot', () => {
mutations.SET_ROOT(localState, true);
expect(localState.isRoot).toBeTruthy();
expect(localState.isInitialRoot).toBeTruthy();
mutations.SET_ROOT(localState, false);
expect(localState.isRoot).toBeFalsy();
expect(localState.isInitialRoot).toBeFalsy();
});
});
describe('SET_LEFT_PANEL_COLLAPSED', () => { describe('SET_LEFT_PANEL_COLLAPSED', () => {
it('sets left panel collapsed', () => { it('sets left panel collapsed', () => {
mutations.SET_LEFT_PANEL_COLLAPSED(localState, true); mutations.SET_LEFT_PANEL_COLLAPSED(localState, true);
......
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