improvements to the design
This commit is contained in:
parent
8de5cea076
commit
201afb0f85
|
@ -1,47 +0,0 @@
|
|||
<script>
|
||||
import icon from '~/vue_shared/components/icon.vue';
|
||||
import repoTree from './ide_repo_tree.vue';
|
||||
import newDropdown from './new_dropdown/index.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
repoTree,
|
||||
icon,
|
||||
newDropdown,
|
||||
},
|
||||
props: {
|
||||
projectId: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
branch: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="branch-container">
|
||||
<div class="branch-header">
|
||||
<div class="branch-header-title str-truncated ref-name">
|
||||
<icon
|
||||
name="branch"
|
||||
:size="12"
|
||||
/>
|
||||
{{ branch.name }}
|
||||
</div>
|
||||
<div class="branch-header-btns">
|
||||
<new-dropdown
|
||||
:project-id="projectId"
|
||||
:branch="branch.name"
|
||||
path=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<repo-tree
|
||||
:tree="branch.tree"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
|
@ -1,24 +0,0 @@
|
|||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import BranchesTree from './ide_project_branches_tree.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BranchesTree,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentProjectWithTree']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="projects-sidebar">
|
||||
<branches-tree
|
||||
v-for="branch in currentProjectWithTree.branches"
|
||||
:key="branch.name"
|
||||
:project-id="currentProjectWithTree.path_with_namespace"
|
||||
:branch="branch"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
|
@ -5,14 +5,13 @@ import icon from '~/vue_shared/components/icon.vue';
|
|||
import panelResizer from '~/vue_shared/components/panel_resizer.vue';
|
||||
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
|
||||
import Identicon from '../../vue_shared/components/identicon.vue';
|
||||
import projectTree from './ide_project_tree.vue';
|
||||
import IdeTree from './ide_tree.vue';
|
||||
import ResizablePanel from './resizable_panel.vue';
|
||||
import ActivityBar from './activity_bar.vue';
|
||||
import CommitSection from './repo_commit_section.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
projectTree,
|
||||
icon,
|
||||
panelResizer,
|
||||
skeletonLoadingContainer,
|
||||
|
@ -21,10 +20,11 @@ export default {
|
|||
ProjectAvatarImage,
|
||||
Identicon,
|
||||
CommitSection,
|
||||
IdeTree,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['loading']),
|
||||
...mapGetters(['currentProjectWithTree', 'activityBarComponent']),
|
||||
...mapState(['loading', 'currentBranchId']),
|
||||
...mapGetters(['currentProject', 'activityBarComponent']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -51,29 +51,39 @@ export default {
|
|||
<template v-else>
|
||||
<div class="context-header">
|
||||
<a
|
||||
:title="currentProjectWithTree.name"
|
||||
:href="currentProjectWithTree.web_url"
|
||||
:href="currentProject.web_url"
|
||||
>
|
||||
<div
|
||||
v-if="currentProjectWithTree.avatar_url"
|
||||
v-if="currentProject.avatar_url"
|
||||
class="avatar-container s40 project-avatar"
|
||||
>
|
||||
<project-avatar-image
|
||||
class="avatar-container project-avatar"
|
||||
:link-href="currentProjectWithTree.path"
|
||||
:img-src="currentProjectWithTree.avatar_url"
|
||||
:img-alt="currentProjectWithTree.name"
|
||||
:link-href="currentProject.path"
|
||||
:img-src="currentProject.avatar_url"
|
||||
:img-alt="currentProject.name"
|
||||
:img-size="40"
|
||||
/>
|
||||
</div>
|
||||
<identicon
|
||||
v-else
|
||||
size-class="s40"
|
||||
:entity-id="currentProjectWithTree.id"
|
||||
:entity-name="currentProjectWithTree.name"
|
||||
:entity-id="currentProject.id"
|
||||
:entity-name="currentProject.name"
|
||||
/>
|
||||
<div class="sidebar-context-title">
|
||||
{{ currentProjectWithTree.name }}
|
||||
<div class="ide-sidebar-project-title">
|
||||
<div class="sidebar-context-title">
|
||||
{{ currentProject.name }}
|
||||
</div>
|
||||
<div
|
||||
v-if="currentBranchId !== ''"
|
||||
class="sidebar-context-title ide-sidebar-branch-title"
|
||||
>
|
||||
<icon
|
||||
name="branch"
|
||||
css-classes="append-right-5"
|
||||
/>{{ currentBranchId }}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -86,3 +96,15 @@ export default {
|
|||
</div>
|
||||
</resizable-panel>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.ide-sidebar-branch-title {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.ide-sidebar-branch-title svg {
|
||||
position: relative;
|
||||
top: 3px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
<script>
|
||||
import { mapGetters, mapState } from 'vuex';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import SkeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
|
||||
import RepoFile from './repo_file.vue';
|
||||
import NewDropdown from './new_dropdown/index.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Icon,
|
||||
RepoFile,
|
||||
SkeletonLoadingContainer,
|
||||
NewDropdown,
|
||||
},
|
||||
props: {
|
||||
tree: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
computed: {
|
||||
...mapState(['currentBranchId']),
|
||||
...mapGetters(['currentProject', 'currentTree']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -20,7 +23,7 @@ export default {
|
|||
<div
|
||||
class="ide-file-list"
|
||||
>
|
||||
<template v-if="tree.loading">
|
||||
<template v-if="!currentTree || currentTree.loading">
|
||||
<div
|
||||
class="multi-file-loading-container"
|
||||
v-for="n in 3"
|
||||
|
@ -30,8 +33,16 @@ export default {
|
|||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<header class="ide-tree-header">
|
||||
{{ __('Edit') }}
|
||||
<new-dropdown
|
||||
:project-id="currentProject.name_with_namespace"
|
||||
:branch="currentBranchId"
|
||||
path=""
|
||||
/>
|
||||
</header>
|
||||
<repo-file
|
||||
v-for="file in tree.tree"
|
||||
v-for="file in currentTree.tree"
|
||||
:key="file.key"
|
||||
:file="file"
|
||||
:level="0"
|
|
@ -63,6 +63,8 @@ router.beforeEach((to, from, next) => {
|
|||
const fullProjectId = `${to.params.namespace}/${to.params.project}`;
|
||||
|
||||
if (to.params.branch) {
|
||||
store.commit('SET_CURRENT_BRANCH', to.params.branch);
|
||||
|
||||
store.dispatch('getBranchData', {
|
||||
projectId: fullProjectId,
|
||||
branchId: to.params.branch,
|
||||
|
|
|
@ -23,18 +23,6 @@ export const projectsWithTrees = state =>
|
|||
};
|
||||
});
|
||||
|
||||
export const currentProjectWithTree = state => ({
|
||||
...state.projects[state.currentProjectId],
|
||||
branches: Object.keys(state.projects[state.currentProjectId].branches).map(branchId => {
|
||||
const branch = state.projects[state.currentProjectId].branches[branchId];
|
||||
|
||||
return {
|
||||
...branch,
|
||||
tree: state.trees[branch.treeId],
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
export const currentMergeRequest = state => {
|
||||
if (state.projects[state.currentProjectId]) {
|
||||
return state.projects[state.currentProjectId].mergeRequests[state.currentMergeRequestId];
|
||||
|
@ -44,6 +32,9 @@ export const currentMergeRequest = state => {
|
|||
|
||||
export const currentProject = state => state.projects[state.currentProjectId];
|
||||
|
||||
export const currentTree = state =>
|
||||
state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
|
||||
|
||||
// eslint-disable-next-line no-confusing-arrow
|
||||
export const currentIcon = state =>
|
||||
state.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right';
|
||||
|
@ -55,7 +46,7 @@ export const hasMergeRequest = state => !!state.currentMergeRequestId;
|
|||
export const activityBarComponent = state => {
|
||||
switch (state.currentActivityView) {
|
||||
case ActivityBarViews.edit:
|
||||
return 'project-tree';
|
||||
return 'ide-tree';
|
||||
case ActivityBarViews.commit:
|
||||
return 'commit-section';
|
||||
default:
|
||||
|
|
|
@ -446,25 +446,6 @@
|
|||
border-top: 1px solid $white-dark;
|
||||
border-top-left-radius: $border-radius-small;
|
||||
}
|
||||
|
||||
.branch-header {
|
||||
background: $white-dark;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.branch-header-title {
|
||||
flex: 1;
|
||||
padding: $grid-size $gl-padding;
|
||||
font-weight: $gl-font-weight-bold;
|
||||
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
.branch-header-btns {
|
||||
padding: $gl-vert-padding $gl-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.multi-file-context-bar-icon {
|
||||
|
@ -901,3 +882,16 @@
|
|||
background: transparent;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.ide-tree-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
border-bottom: 1px solid $white-dark;
|
||||
|
||||
.ide-new-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ feature 'Multi-file editor new directory', :js do
|
|||
|
||||
wait_for_requests
|
||||
|
||||
find('.js-ide-commit-mode').click
|
||||
|
||||
fill_in('commit-message', with: 'commit message ide')
|
||||
|
||||
click_button('Commit')
|
||||
|
|
|
@ -34,6 +34,8 @@ feature 'Multi-file editor new file', :js do
|
|||
|
||||
wait_for_requests
|
||||
|
||||
find('.js-ide-commit-mode').click
|
||||
|
||||
fill_in('commit-message', with: 'commit message ide')
|
||||
|
||||
click_button('Commit')
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import ProjectTree from '~/ide/components/ide_project_tree.vue';
|
||||
import createComponent from 'spec/helpers/vue_mount_component_helper';
|
||||
|
||||
describe('IDE project tree', () => {
|
||||
const Component = Vue.extend(ProjectTree);
|
||||
let vm;
|
||||
|
||||
beforeEach(() => {
|
||||
vm = createComponent(Component, {
|
||||
project: {
|
||||
id: 1,
|
||||
name: 'test',
|
||||
web_url: gl.TEST_HOST,
|
||||
avatar_url: '',
|
||||
branches: [],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
});
|
||||
|
||||
it('renders identicon when projct has no avatar', () => {
|
||||
expect(vm.$el.querySelector('.identicon')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders avatar image if project has avatar', done => {
|
||||
vm.project.avatar_url = gl.TEST_HOST;
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(vm.$el.querySelector('.identicon')).toBeNull();
|
||||
expect(vm.$el.querySelector('img.avatar')).not.toBeNull();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -3,6 +3,7 @@ import store from '~/ide/stores';
|
|||
import ideSidebar from '~/ide/components/ide_side_bar.vue';
|
||||
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||
import { resetStore } from '../helpers';
|
||||
import { projectData } from '../mock_data';
|
||||
|
||||
describe('IdeSidebar', () => {
|
||||
let vm;
|
||||
|
@ -10,6 +11,10 @@ describe('IdeSidebar', () => {
|
|||
beforeEach(() => {
|
||||
const Component = Vue.extend(ideSidebar);
|
||||
|
||||
store.state.currentProjectId = 'abcproject';
|
||||
store.state.projects.abcproject = projectData;
|
||||
store.state.currentActivityView = null;
|
||||
|
||||
vm = createComponentWithStore(Component, store).$mount();
|
||||
});
|
||||
|
||||
|
@ -20,21 +25,15 @@ describe('IdeSidebar', () => {
|
|||
});
|
||||
|
||||
it('renders a sidebar', () => {
|
||||
expect(
|
||||
vm.$el.querySelector('.multi-file-commit-panel-inner'),
|
||||
).not.toBeNull();
|
||||
expect(vm.$el.querySelector('.multi-file-commit-panel-inner')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('renders loading icon component', done => {
|
||||
vm.$store.state.loading = true;
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(
|
||||
vm.$el.querySelector('.multi-file-loading-container'),
|
||||
).not.toBeNull();
|
||||
expect(
|
||||
vm.$el.querySelectorAll('.multi-file-loading-container').length,
|
||||
).toBe(3);
|
||||
expect(vm.$el.querySelector('.multi-file-loading-container')).not.toBeNull();
|
||||
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toBe(3);
|
||||
|
||||
done();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import Vue from 'vue';
|
||||
import ideRepoTree from '~/ide/components/ide_repo_tree.vue';
|
||||
import IdeTree from '~/ide/components/ide_tree.vue';
|
||||
import createComponent from '../../helpers/vue_mount_component_helper';
|
||||
import { file } from '../helpers';
|
||||
|
||||
|
@ -8,7 +8,7 @@ describe('IdeRepoTree', () => {
|
|||
let tree;
|
||||
|
||||
beforeEach(() => {
|
||||
const IdeRepoTree = Vue.extend(ideRepoTree);
|
||||
const IdeRepoTree = Vue.extend(IdeTree);
|
||||
|
||||
tree = {
|
||||
tree: [file()],
|
||||
|
@ -33,9 +33,7 @@ describe('IdeRepoTree', () => {
|
|||
tree.loading = true;
|
||||
|
||||
vm.$nextTick(() => {
|
||||
expect(
|
||||
vm.$el.querySelectorAll('.multi-file-loading-container').length,
|
||||
).toEqual(3);
|
||||
expect(vm.$el.querySelectorAll('.multi-file-loading-container').length).toEqual(3);
|
||||
|
||||
done();
|
||||
});
|
|
@ -12,10 +12,10 @@ describe('RepoCommitSection', () => {
|
|||
function createComponent() {
|
||||
const Component = Vue.extend(repoCommitSection);
|
||||
|
||||
vm = createComponentWithStore(Component, store, {
|
||||
noChangesStateSvgPath: 'svg',
|
||||
committedStateSvgPath: 'commitsvg',
|
||||
});
|
||||
store.state.noChangesStateSvgPath = 'svg';
|
||||
store.state.committedStateSvgPath = 'commitsvg';
|
||||
|
||||
vm = createComponentWithStore(Component, store);
|
||||
|
||||
vm.$store.state.currentProjectId = 'abcproject';
|
||||
vm.$store.state.currentBranchId = 'master';
|
||||
|
@ -75,33 +75,25 @@ describe('RepoCommitSection', () => {
|
|||
resetStore(vm.$store);
|
||||
const Component = Vue.extend(repoCommitSection);
|
||||
|
||||
vm = createComponentWithStore(Component, store, {
|
||||
noChangesStateSvgPath: 'nochangessvg',
|
||||
committedStateSvgPath: 'svg',
|
||||
}).$mount();
|
||||
store.state.noChangesStateSvgPath = 'nochangessvg';
|
||||
store.state.committedStateSvgPath = 'svg';
|
||||
|
||||
expect(
|
||||
vm.$el.querySelector('.js-empty-state').textContent.trim(),
|
||||
).toContain('No changes');
|
||||
expect(
|
||||
vm.$el.querySelector('.js-empty-state img').getAttribute('src'),
|
||||
).toBe('nochangessvg');
|
||||
vm = createComponentWithStore(Component, store).$mount();
|
||||
|
||||
expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('No changes');
|
||||
expect(vm.$el.querySelector('.js-empty-state img').getAttribute('src')).toBe('nochangessvg');
|
||||
});
|
||||
});
|
||||
|
||||
it('renders a commit section', () => {
|
||||
const changedFileElements = [
|
||||
...vm.$el.querySelectorAll('.multi-file-commit-list li'),
|
||||
];
|
||||
const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')];
|
||||
const submitCommit = vm.$el.querySelector('form .btn');
|
||||
|
||||
expect(vm.$el.querySelector('.multi-file-commit-form')).not.toBeNull();
|
||||
expect(changedFileElements.length).toEqual(2);
|
||||
|
||||
changedFileElements.forEach((changedFile, i) => {
|
||||
expect(changedFile.textContent.trim()).toContain(
|
||||
vm.$store.state.changedFiles[i].path,
|
||||
);
|
||||
expect(changedFile.textContent.trim()).toContain(vm.$store.state.changedFiles[i].path);
|
||||
});
|
||||
|
||||
expect(submitCommit.disabled).toBeTruthy();
|
||||
|
@ -117,9 +109,7 @@ describe('RepoCommitSection', () => {
|
|||
|
||||
getSetTimeoutPromise()
|
||||
.then(() => {
|
||||
expect(vm.$store.state.commit.commitMessage).toBe(
|
||||
'testing commit message',
|
||||
);
|
||||
expect(vm.$store.state.commit.commitMessage).toBe('testing commit message');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
|
@ -127,9 +117,7 @@ describe('RepoCommitSection', () => {
|
|||
|
||||
describe('discard draft button', () => {
|
||||
it('hidden when commitMessage is empty', () => {
|
||||
expect(
|
||||
vm.$el.querySelector('.multi-file-commit-form .btn-default'),
|
||||
).toBeNull();
|
||||
expect(vm.$el.querySelector('.multi-file-commit-form .btn-default')).toBeNull();
|
||||
});
|
||||
|
||||
it('resets commitMessage when clicking discard button', done => {
|
||||
|
@ -141,9 +129,7 @@ describe('RepoCommitSection', () => {
|
|||
})
|
||||
.then(Vue.nextTick)
|
||||
.then(() => {
|
||||
expect(vm.$store.state.commit.commitMessage).not.toBe(
|
||||
'testing commit message',
|
||||
);
|
||||
expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const projectData = {
|
||||
id: 1,
|
||||
name: 'abcproject',
|
||||
web_url: '',
|
||||
avatar_url: '',
|
||||
path: '',
|
||||
branches: {
|
||||
master: {
|
||||
treeId: 'abcproject/master',
|
||||
},
|
||||
},
|
||||
};
|
Loading…
Reference in New Issue