Commit 45b9d60b authored by Phil Hughes's avatar Phil Hughes

template improvements

[ci skip]
parent 3e2d0e1a
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
<button <button
type="button" type="button"
class="btn btn-blank multi-file-discard-btn" class="btn btn-blank multi-file-discard-btn"
@click="discardFileChanges(file)" @click="discardFileChanges(file.path)"
> >
Discard Discard
</button> </button>
......
...@@ -69,6 +69,7 @@ ...@@ -69,6 +69,7 @@
/> />
<repo-editor <repo-editor
class="multi-file-edit-pane-content" class="multi-file-edit-pane-content"
:file="activeFile"
/> />
<repo-file-buttons <repo-file-buttons
:file="activeFile" :file="activeFile"
......
<script> <script>
import { mapState } from 'vuex'; import { mapGetters, mapState } from 'vuex';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import panelResizer from '~/vue_shared/components/panel_resizer.vue'; import panelResizer from '~/vue_shared/components/panel_resizer.vue';
import repoCommitSection from './repo_commit_section.vue'; import repoCommitSection from './repo_commit_section.vue';
...@@ -27,9 +27,9 @@ ...@@ -27,9 +27,9 @@
'changedFiles', 'changedFiles',
'rightPanelCollapsed', 'rightPanelCollapsed',
]), ]),
currentIcon() { ...mapGetters([
return this.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right'; 'currentIcon',
}, ]),
}, },
}; };
</script> </script>
......
...@@ -40,8 +40,10 @@ export default { ...@@ -40,8 +40,10 @@ export default {
/> />
</div> </div>
</div> </div>
<div> <template v-if="branch.tree">
<repo-tree :tree-id="branch.treeId" /> <repo-tree
</div> :tree="branch.tree"
/>
</template>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapGetters } from 'vuex'; import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; import RepoFile from './repo_file.vue';
import repoFile from './repo_file.vue';
export default { export default {
components: { components: {
repoFile, RepoFile,
skeletonLoadingContainer, SkeletonLoadingContainer,
}, },
props: { props: {
treeId: { tree: {
type: String, type: Object,
required: true, required: true,
}, },
}, },
computed: {
...mapState([
'trees',
]),
...mapGetters([
'treeList',
]),
selctedTree() {
return this.trees[this.treeId].tree;
},
showLoading() {
return !this.trees[this.treeId] || this.trees[this.treeId].loading;
},
},
}; };
</script> </script>
<template> <template>
<div <div
class="ide-file-list" class="ide-file-list"
v-if="treeId"
> >
<template v-if="showLoading"> <template v-if="tree.loading">
<div <div
class="multi-file-loading-container" class="multi-file-loading-container"
v-for="n in 3" v-for="n in 3"
...@@ -46,7 +30,7 @@ export default { ...@@ -46,7 +30,7 @@ export default {
</div> </div>
</template> </template>
<repo-file <repo-file
v-for="file in treeList" v-for="file in tree.tree"
:key="file.key" :key="file.key"
:file="file" :file="file"
/> />
......
<script> <script>
import { mapState } from 'vuex'; import { mapState, mapGetters } from 'vuex';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import panelResizer from '~/vue_shared/components/panel_resizer.vue'; import panelResizer from '~/vue_shared/components/panel_resizer.vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
...@@ -17,7 +17,9 @@ ...@@ -17,7 +17,9 @@
computed: { computed: {
...mapState([ ...mapState([
'loading', 'loading',
'projects', ]),
...mapGetters([
'projectsWithTrees',
]), ]),
}, },
}; };
...@@ -40,7 +42,7 @@ ...@@ -40,7 +42,7 @@
</div> </div>
</template> </template>
<project-tree <project-tree
v-for="project in projects" v-for="project in projectsWithTrees"
:key="project.id" :key="project.id"
:project="project" :project="project"
/> />
......
...@@ -6,22 +6,24 @@ import monacoLoader from '../monaco_loader'; ...@@ -6,22 +6,24 @@ import monacoLoader from '../monaco_loader';
import Editor from '../lib/editor'; import Editor from '../lib/editor';
export default { export default {
props: {
file: {
type: Object,
required: true,
},
},
computed: { computed: {
...mapGetters([
'activeFile',
]),
...mapState([ ...mapState([
'leftPanelCollapsed', 'leftPanelCollapsed',
'rightPanelCollapsed', 'rightPanelCollapsed',
'panelResizing',
]), ]),
shouldHideEditor() { shouldHideEditor() {
return this.activeFile && this.activeFile.binary && !this.activeFile.raw; return this.file && this.file.binary && !this.file.raw;
}, },
}, },
watch: { watch: {
activeFile(oldVal, newVal) { file(oldVal, newVal) {
if (newVal.path !== this.activeFile.path) { if (newVal.path !== this.file.path) {
this.initMonaco(); this.initMonaco();
} }
}, },
...@@ -31,11 +33,6 @@ export default { ...@@ -31,11 +33,6 @@ export default {
rightPanelCollapsed() { rightPanelCollapsed() {
this.editor.updateDimensions(); this.editor.updateDimensions();
}, },
panelResizing(isResizing) {
if (isResizing === false) {
this.editor.updateDimensions();
}
},
}, },
beforeDestroy() { beforeDestroy() {
this.editor.dispose(); this.editor.dispose();
...@@ -64,7 +61,7 @@ export default { ...@@ -64,7 +61,7 @@ export default {
this.editor.clearEditor(); this.editor.clearEditor();
this.getRawFileData(this.activeFile) this.getRawFileData(this.file)
.then(() => { .then(() => {
this.editor.createInstance(this.$refs.editor); this.editor.createInstance(this.$refs.editor);
}) })
...@@ -75,9 +72,9 @@ export default { ...@@ -75,9 +72,9 @@ export default {
}); });
}, },
setupEditor() { setupEditor() {
if (!this.activeFile) return; if (!this.file) return;
this.model = this.editor.createModel(this.activeFile); this.model = this.editor.createModel(this.file);
this.editor.attachModel(this.model); this.editor.attachModel(this.model);
...@@ -101,8 +98,8 @@ export default { ...@@ -101,8 +98,8 @@ export default {
}); });
this.editor.setPosition({ this.editor.setPosition({
lineNumber: this.activeFile.editorRow, lineNumber: this.file.editorRow,
column: this.activeFile.editorColumn, column: this.file.editorColumn,
}); });
// Handle File Language // Handle File Language
......
...@@ -3,9 +3,8 @@ ...@@ -3,9 +3,8 @@
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import fileIcon from '~/vue_shared/components/file_icon.vue'; import fileIcon from '~/vue_shared/components/file_icon.vue';
import newDropdown from './new_dropdown/index.vue'; import newDropdown from './new_dropdown/index.vue';
import fileStatusIcon from './repo_file_status_icon.vue';
import fileStatusIcon from 'ee/ide/components/repo_file_status_icon.vue'; // eslint-disable-line import/first import changedFileIcon from './changed_file_icon.vue';
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue'; // eslint-disable-line import/first
export default { export default {
name: 'RepoFile', name: 'RepoFile',
...@@ -24,39 +23,25 @@ ...@@ -24,39 +23,25 @@
type: Object, type: Object,
required: true, required: true,
}, },
showExtraColumns: {
type: Boolean,
default: false,
},
}, },
computed: { computed: {
isSubmodule() {
return this.file.type === 'submodule';
},
isTree() { isTree() {
return this.file.type === 'tree'; return this.file.type === 'tree';
}, },
levelIndentation() { isBlob() {
if (this.file.level > 0) { return this.file.type === 'blob';
return {
marginLeft: `${this.file.level * 16}px`,
};
}
return {};
}, },
shortId() { levelIndentation() {
return this.file.id.substr(0, 8); return {
marginLeft: `${this.file.level * 16}px`,
};
}, },
fileClass() { fileClass() {
if (this.file.type === 'blob') { return {
if (this.file.active) { 'file-open': this.isBlob && this.file.opened,
return 'file-open file-active'; 'file-active': this.isBlob && this.file.active,
} 'folder': this.isTree,
return this.file.opened ? 'file-open' : ''; };
} else if (this.file.type === 'tree') {
return 'folder';
}
return '';
}, },
}, },
updated() { updated() {
...@@ -88,21 +73,24 @@ ...@@ -88,21 +73,24 @@
<div <div
class="file-name" class="file-name"
@click="clickFile(file)" @click="clickFile(file)"
role="button"
> >
<a <span
class="ide-file-name str-truncated" class="ide-file-name str-truncated"
:style="levelIndentation"
> >
<file-icon <file-icon
:file-name="file.name" :file-name="file.name"
:loading="file.loading" :loading="file.loading"
:folder="file.type === 'tree'" :folder="isTree"
:opened="file.opened" :opened="file.opened"
:style="levelIndentation"
:size="16" :size="16"
/> />
{{ file.name }} {{ file.name }}
<file-status-icon :file="file" /> <file-status-icon
</a> :file="file"
/>
</span>
<new-dropdown <new-dropdown
v-if="isTree" v-if="isTree"
:project-id="file.projectId" :project-id="file.projectId"
...@@ -115,17 +103,6 @@ ...@@ -115,17 +103,6 @@
v-if="file.changed || file.tempFile" v-if="file.changed || file.tempFile"
class="prepend-top-5" class="prepend-top-5"
/> />
<template v-if="isSubmodule && file.id">
@
<span class="commit-sha">
<a
@click.stop
:href="file.tree_url"
>
{{ shortId }}
</a>
</span>
</template>
</div> </div>
</div> </div>
<template v-if="file.opened"> <template v-if="file.opened">
......
...@@ -9,10 +9,10 @@ export const setInitialData = ({ commit }, data) => ...@@ -9,10 +9,10 @@ export const setInitialData = ({ commit }, data) =>
export const discardAllChanges = ({ state, commit, dispatch }) => { export const discardAllChanges = ({ state, commit, dispatch }) => {
state.changedFiles.forEach((file) => { state.changedFiles.forEach((file) => {
commit(types.DISCARD_FILE_CHANGES, file); commit(types.DISCARD_FILE_CHANGES, file.path);
if (file.tempFile) { if (file.tempFile) {
dispatch('closeFile', file); dispatch('closeFile', file.path);
} }
}); });
...@@ -74,4 +74,3 @@ export const scrollToTab = () => { ...@@ -74,4 +74,3 @@ export const scrollToTab = () => {
export * from './actions/tree'; export * from './actions/tree';
export * from './actions/file'; export * from './actions/file';
export * from './actions/project'; export * from './actions/project';
export * from './actions/branch';
import flash from '~/flash';
import service from '../../services';
import * as types from '../mutation_types';
export const getBranchData = (
{ commit, state, dispatch },
{ projectId, branchId, force = false } = {},
) => new Promise((resolve, reject) => {
if ((typeof state.projects[`${projectId}`] === 'undefined' ||
!state.projects[`${projectId}`].branches[branchId])
|| force) {
service.getBranchData(`${projectId}`, branchId)
.then(({ data }) => {
const { id } = data.commit;
commit(types.SET_BRANCH, { projectPath: `${projectId}`, branchName: branchId, branch: data });
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
resolve(data);
})
.catch(() => {
flash('Error loading branch data. Please try again.', 'alert', document, null, false, true);
reject(new Error(`Branch not loaded - ${projectId}/${branchId}`));
});
} else {
resolve(state.projects[`${projectId}`].branches[branchId]);
}
});
export const createNewBranch = ({ state, commit }, branch) => service.createBranch(
state.currentProjectId,
{
branch,
ref: state.currentBranchId,
},
)
.then(res => res.json())
.then((data) => {
const branchName = data.name;
const url = location.href.replace(state.currentBranchId, branchName);
if (this.$router) this.$router.push(url);
commit(types.SET_CURRENT_BRANCH, branchName);
});
...@@ -42,9 +42,6 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => { ...@@ -42,9 +42,6 @@ export const setFileActive = ({ commit, state, getters, dispatch }, path) => {
commit(types.SET_FILE_ACTIVE, { path, active: true }); commit(types.SET_FILE_ACTIVE, { path, active: true });
dispatch('scrollToTab'); dispatch('scrollToTab');
// reset hash for line highlighting
location.hash = '';
commit(types.SET_CURRENT_PROJECT, file.projectId); commit(types.SET_CURRENT_PROJECT, file.projectId);
commit(types.SET_CURRENT_BRANCH, file.branchId); commit(types.SET_CURRENT_BRANCH, file.branchId);
}; };
...@@ -141,11 +138,13 @@ export const createTempFile = ({ state, commit, dispatch }, { projectId, branchI ...@@ -141,11 +138,13 @@ export const createTempFile = ({ state, commit, dispatch }, { projectId, branchI
return Promise.resolve(file); return Promise.resolve(file);
}; };
export const discardFileChanges = ({ commit }, file) => { export const discardFileChanges = ({ state, commit }, path) => {
commit(types.DISCARD_FILE_CHANGES, file); const file = state.entries[path];
commit(types.REMOVE_FILE_FROM_CHANGED, file);
commit(types.DISCARD_FILE_CHANGES, path);
commit(types.REMOVE_FILE_FROM_CHANGED, path);
if (file.tempFile && file.opened) { if (file.tempFile && file.opened) {
commit(types.TOGGLE_FILE_OPEN, file.path); commit(types.TOGGLE_FILE_OPEN, path);
} }
}; };
...@@ -2,7 +2,6 @@ import flash from '~/flash'; ...@@ -2,7 +2,6 @@ import flash from '~/flash';
import service from '../../services'; import service from '../../services';
import * as types from '../mutation_types'; import * as types from '../mutation_types';
// eslint-disable-next-line import/prefer-default-export
export const getProjectData = ( export const getProjectData = (
{ commit, state, dispatch }, { commit, state, dispatch },
{ namespace, projectId, force = false } = {}, { namespace, projectId, force = false } = {},
...@@ -25,3 +24,26 @@ export const getProjectData = ( ...@@ -25,3 +24,26 @@ export const getProjectData = (
resolve(state.projects[`${namespace}/${projectId}`]); resolve(state.projects[`${namespace}/${projectId}`]);
} }
}); });
export const getBranchData = (
{ commit, state, dispatch },
{ projectId, branchId, force = false } = {},
) => new Promise((resolve, reject) => {
if ((typeof state.projects[`${projectId}`] === 'undefined' ||
!state.projects[`${projectId}`].branches[branchId])
|| force) {
service.getBranchData(`${projectId}`, branchId)
.then(({ data }) => {
const { id } = data.commit;
commit(types.SET_BRANCH, { projectPath: `${projectId}`, branchName: branchId, branch: data });
commit(types.SET_BRANCH_WORKING_REFERENCE, { projectId, branchId, reference: id });
resolve(data);
})
.catch(() => {
flash('Error loading branch data. Please try again.', 'alert', document, null, false, true);
reject(new Error(`Branch not loaded - ${projectId}/${branchId}`));
});
} else {
resolve(state.projects[`${projectId}`].branches[branchId]);
}
});
...@@ -10,16 +10,13 @@ import { ...@@ -10,16 +10,13 @@ import {
} from '../utils'; } from '../utils';
import FilesDecoratorWorker from '../workers/files_decorator_worker'; import FilesDecoratorWorker from '../workers/files_decorator_worker';
export const toggleTreeOpen = ({ commit, dispatch }, { tree }) => { export const toggleTreeOpen = ({ commit, dispatch }, path) => {
commit(types.TOGGLE_TREE_OPEN, tree); commit(types.TOGGLE_TREE_OPEN, path);
}; };
export const handleTreeEntryAction = ({ commit, dispatch }, row) => { export const handleTreeEntryAction = ({ commit, dispatch }, row) => {
if (row.type === 'tree') { if (row.type === 'tree') {
dispatch('toggleTreeOpen', { dispatch('toggleTreeOpen', row.path);
endpoint: row.url,
tree: row,
});
} else if (row.type === 'submodule') { } else if (row.type === 'submodule') {
commit(types.TOGGLE_LOADING, { entry: row }); commit(types.TOGGLE_LOADING, { entry: row });
visitUrl(row.url); visitUrl(row.url);
...@@ -115,7 +112,7 @@ export const getFiles = ( ...@@ -115,7 +112,7 @@ export const getFiles = (
const selectedTree = state.trees[`${projectId}/${branchId}`]; const selectedTree = state.trees[`${projectId}/${branchId}`];
commit(types.SET_ENTRIES, entries); commit(types.SET_ENTRIES, entries);
commit(types.SET_DIRECTORY_DATA, { tree: selectedTree, data: treeList }); commit(types.SET_DIRECTORY_DATA, { treePath: `${projectId}/${branchId}`, data: treeList });
commit(types.TOGGLE_LOADING, { entry: selectedTree, forceValue: false }); commit(types.TOGGLE_LOADING, { entry: selectedTree, forceValue: false });
worker.terminate(); worker.terminate();
......
...@@ -11,10 +11,21 @@ export const addedFiles = state => state.changedFiles.filter(f => f.tempFile); ...@@ -11,10 +11,21 @@ export const addedFiles = state => state.changedFiles.filter(f => f.tempFile);
export const modifiedFiles = state => state.changedFiles.filter(f => !f.tempFile); export const modifiedFiles = state => state.changedFiles.filter(f => !f.tempFile);
export const treeList = (state) => { export const projectsWithTrees = state => Object.keys(state.projects).map((projectId) => {
const tree = state.trees[`${state.currentProjectId}/master`]; const project = state.projects[projectId];
if (!tree) return []; return {
...project,
branches: Object.keys(project.branches).map((branchId) => {
const branch = project.branches[branchId];
return tree.tree; return {
}; ...branch,
tree: state.trees[branch.treeId],
};
}),
};
});
export const currentIcon = state =>
(state.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right');
...@@ -7,16 +7,14 @@ export default { ...@@ -7,16 +7,14 @@ export default {
}); });
}, },
[types.SET_BRANCH](state, { projectPath, branchName, branch }) { [types.SET_BRANCH](state, { projectPath, branchName, branch }) {
// Add client side properties
Object.assign(branch, {
treeId: `${projectPath}/${branchName}`,
active: true,
workingReference: '',
});
Object.assign(state.projects[projectPath], { Object.assign(state.projects[projectPath], {
branches: { branches: {
[branchName]: branch, [branchName]: {
...branch,
treeId: `${projectPath}/${branchName}`,
active: true,
workingReference: '',
},
}, },
}); });
}, },
......
...@@ -59,9 +59,9 @@ export default { ...@@ -59,9 +59,9 @@ export default {
editorColumn, editorColumn,
}); });
}, },
[types.DISCARD_FILE_CHANGES](state, file) { [types.DISCARD_FILE_CHANGES](state, path) {
Object.assign(state.entries[file.path], { Object.assign(state.entries[path], {
content: state.entries[file.path].raw, content: state.entries[path].raw,
changed: false, changed: false,
}); });
}, },
......
import * as types from '../mutation_types'; import * as types from '../mutation_types';
export default { export default {
[types.TOGGLE_TREE_OPEN](state, tree) { [types.TOGGLE_TREE_OPEN](state, path) {
Object.assign(state.entries[tree.path], { Object.assign(state.entries[path], {
opened: !state.entries[tree.path].opened, opened: !state.entries[path].opened,
}); });
}, },
[types.CREATE_TREE](state, { treePath }) { [types.CREATE_TREE](state, { treePath }) {
...@@ -16,9 +16,13 @@ export default { ...@@ -16,9 +16,13 @@ export default {
}), }),
}); });
}, },
[types.SET_DIRECTORY_DATA](state, { data, tree }) { [types.SET_DIRECTORY_DATA](state, { data, treePath }) {
Object.assign(tree, { Object.assign(state, {
tree: data, trees: Object.assign(state.trees, {
[treePath]: {
tree: data,
},
}),
}); });
}, },
[types.SET_LAST_COMMIT_URL](state, { tree = state, url }) { [types.SET_LAST_COMMIT_URL](state, { tree = state, url }) {
......
...@@ -27,6 +27,7 @@ self.addEventListener('message', (e) => { ...@@ -27,6 +27,7 @@ self.addEventListener('message', (e) => {
url: `/${projectId}/tree/${branchId}/${folderPath}`, url: `/${projectId}/tree/${branchId}/${folderPath}`,
level: parentFolder ? parentFolder.level + 1 : folderLevel, level: parentFolder ? parentFolder.level + 1 : folderLevel,
type: 'tree', type: 'tree',
parentTreeUrl: parentFolder ? parentFolder.url : `/${projectId}/tree/${branchId}/`,
}); });
Object.assign(acc, { Object.assign(acc, {
...@@ -58,6 +59,7 @@ self.addEventListener('message', (e) => { ...@@ -58,6 +59,7 @@ self.addEventListener('message', (e) => {
url: `/${projectId}/blob/${branchId}/${path}`, url: `/${projectId}/blob/${branchId}/${path}`,
level: fileFolder ? fileFolder.level + 1 : 0, level: fileFolder ? fileFolder.level + 1 : 0,
type: 'blob', type: 'blob',
parentTreeUrl: fileFolder ? fileFolder.url : `/${projectId}/blob/${branchId}`,
}); });
Object.assign(acc, { Object.assign(acc, {
......
import store from 'ee/ide/stores';
import service from 'ee/ide/services';
import { resetStore } from '../../helpers';
describe('Multi-file store branch actions', () => {
afterEach(() => {
resetStore(store);
});
describe('createNewBranch', () => {
beforeEach(() => {
spyOn(service, 'createBranch').and.returnValue(Promise.resolve({
json: () => ({
name: 'testing',
}),
}));
spyOn(history, 'pushState');
store.state.currentProjectId = 'abcproject';
store.state.currentBranchId = 'testing';
store.state.projects.abcproject = {
branches: {
master: {
workingReference: '1',
},
},
};
});
it('creates new branch', (done) => {
store.dispatch('createNewBranch', 'master')
.then(() => {
expect(store.state.currentBranchId).toBe('testing');
expect(service.createBranch).toHaveBeenCalledWith('abcproject', {
branch: 'master',
ref: 'testing',
});
done();
})
.catch(done.fail);
});
});
});
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