diff options
14 files changed, 117 insertions, 207 deletions
diff --git a/app/assets/javascripts/ide/components/ide_project_branches_tree.vue b/app/assets/javascripts/ide/components/ide_project_branches_tree.vue deleted file mode 100644 index eb2749e6151..00000000000 --- a/app/assets/javascripts/ide/components/ide_project_branches_tree.vue +++ /dev/null @@ -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> diff --git a/app/assets/javascripts/ide/components/ide_project_tree.vue b/app/assets/javascripts/ide/components/ide_project_tree.vue deleted file mode 100644 index 3179300a44f..00000000000 --- a/app/assets/javascripts/ide/components/ide_project_tree.vue +++ /dev/null @@ -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> diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue index 77c958a6f8f..b14e4f21f48 100644 --- a/app/assets/javascripts/ide/components/ide_side_bar.vue +++ b/app/assets/javascripts/ide/components/ide_side_bar.vue @@ -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> diff --git a/app/assets/javascripts/ide/components/ide_repo_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue index e6af88e04bc..ed83bf4109b 100644 --- a/app/assets/javascripts/ide/components/ide_repo_tree.vue +++ b/app/assets/javascripts/ide/components/ide_tree.vue @@ -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" diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js index 4a0a303d5a6..9f475e9e9b0 100644 --- a/app/assets/javascripts/ide/ide_router.js +++ b/app/assets/javascripts/ide/ide_router.js @@ -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, diff --git a/app/assets/javascripts/ide/stores/getters.js b/app/assets/javascripts/ide/stores/getters.js index c2899f12f18..4cdc10f6566 100644 --- a/app/assets/javascripts/ide/stores/getters.js +++ b/app/assets/javascripts/ide/stores/getters.js @@ -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: diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index e9f4abd91d2..7fcf2602e63 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -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; + } +} diff --git a/spec/features/projects/tree/create_directory_spec.rb b/spec/features/projects/tree/create_directory_spec.rb index d96c7e655ba..77436268b3d 100644 --- a/spec/features/projects/tree/create_directory_spec.rb +++ b/spec/features/projects/tree/create_directory_spec.rb @@ -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') diff --git a/spec/features/projects/tree/create_file_spec.rb b/spec/features/projects/tree/create_file_spec.rb index a4cbd5cf766..a54dbc74058 100644 --- a/spec/features/projects/tree/create_file_spec.rb +++ b/spec/features/projects/tree/create_file_spec.rb @@ -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') diff --git a/spec/javascripts/ide/components/ide_project_tree_spec.js b/spec/javascripts/ide/components/ide_project_tree_spec.js deleted file mode 100644 index 657682cb39c..00000000000 --- a/spec/javascripts/ide/components/ide_project_tree_spec.js +++ /dev/null @@ -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(); - }); - }); -}); diff --git a/spec/javascripts/ide/components/ide_side_bar_spec.js b/spec/javascripts/ide/components/ide_side_bar_spec.js index 699dae1ce2f..fb393e61d56 100644 --- a/spec/javascripts/ide/components/ide_side_bar_spec.js +++ b/spec/javascripts/ide/components/ide_side_bar_spec.js @@ -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(); }); diff --git a/spec/javascripts/ide/components/ide_repo_tree_spec.js b/spec/javascripts/ide/components/ide_tree_spec.js index e0fbc90ca61..47c29e07b9a 100644 --- a/spec/javascripts/ide/components/ide_repo_tree_spec.js +++ b/spec/javascripts/ide/components/ide_tree_spec.js @@ -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(); }); diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 113ade269e9..c5a12ad6c72 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -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(); - - expect( - vm.$el.querySelector('.js-empty-state').textContent.trim(), - ).toContain('No changes'); - expect( - vm.$el.querySelector('.js-empty-state img').getAttribute('src'), - ).toBe('nochangessvg'); + store.state.noChangesStateSvgPath = 'nochangessvg'; + store.state.committedStateSvgPath = 'svg'; + + 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); diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js new file mode 100644 index 00000000000..aef0df81baf --- /dev/null +++ b/spec/javascripts/ide/mock_data.js @@ -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', + }, + }, +}; |