summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipa Lacerda <filipa@gitlab.com>2018-05-04 13:40:38 +0000
committerFilipa Lacerda <filipa@gitlab.com>2018-05-04 13:40:38 +0000
commit9f2f8679bec1e2d4161c429c2e6db80a20e376c9 (patch)
tree3e6f89e5dc2cb6e33c281fbae32ebe4e52d1968d
parent805302c0c09f0c6a3226efd2d3fca1b46015f9e0 (diff)
parent14b8ac3e2a1c29c7f86391118f6916959a1337c6 (diff)
downloadgitlab-ce-9f2f8679bec1e2d4161c429c2e6db80a20e376c9.tar.gz
Merge branch 'ide-sidebar-merge-request' into '44846-improve-web-ide-left-panel-and-modes'
Added merge request review to IDE sidebar See merge request gitlab-org/gitlab-ce!18709
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue3
-rw-r--r--app/assets/javascripts/ide/components/editor_mode_dropdown.vue80
-rw-r--r--app/assets/javascripts/ide/components/ide_review.vue42
-rw-r--r--app/assets/javascripts/ide/components/ide_side_bar.vue22
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue9
-rw-r--r--app/assets/javascripts/ide/constants.js6
-rw-r--r--app/assets/javascripts/ide/ide_router.js5
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js9
-rw-r--r--app/assets/javascripts/ide/stores/state.js4
-rw-r--r--app/assets/stylesheets/pages/repo.scss28
-rw-r--r--spec/javascripts/ide/components/ide_review_spec.js36
-rw-r--r--spec/javascripts/ide/mock_data.js1
12 files changed, 165 insertions, 80 deletions
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index 872302840e2..03f3e4de83c 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -3,6 +3,7 @@ import { mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
import StageButton from './stage_button.vue';
import UnstageButton from './unstage_button.vue';
+import { viewerTypes } from '../../constants';
export default {
components: {
@@ -53,7 +54,7 @@ export default {
keyPrefix: this.keyPrefix.toLowerCase(),
}).then(changeViewer => {
if (changeViewer) {
- this.updateViewer('diff');
+ this.updateViewer(viewerTypes.diff);
}
});
},
diff --git a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
index 0c44a755f56..b9af4d27145 100644
--- a/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
+++ b/app/assets/javascripts/ide/components/editor_mode_dropdown.vue
@@ -1,28 +1,15 @@
<script>
-import Icon from '~/vue_shared/components/icon.vue';
import { __, sprintf } from '~/locale';
+import { viewerTypes } from '../constants';
export default {
- components: {
- Icon,
- },
props: {
- hasChanges: {
- type: Boolean,
- required: false,
- default: false,
- },
- mergeRequestId: {
- type: String,
- required: false,
- default: '',
- },
viewer: {
type: String,
required: true,
},
- showShadow: {
- type: Boolean,
+ mergeRequestId: {
+ type: Number,
required: true,
},
},
@@ -38,84 +25,45 @@ export default {
this.$emit('click', mode);
},
},
+ viewerTypes,
};
</script>
<template>
<div
class="dropdown"
- :class="{
- shadow: showShadow,
- }"
>
<button
type="button"
- class="btn btn-primary btn-sm"
- :class="{
- 'btn-inverted': hasChanges,
- }"
+ class="btn btn-link"
data-toggle="dropdown"
>
- <template v-if="viewer === 'mrdiff' && mergeRequestId">
- {{ mergeReviewLine }}
- </template>
- <template v-else-if="viewer === 'editor'">
- {{ __('Editing') }}
- </template>
- <template v-else>
- {{ __('Reviewing') }}
- </template>
- <icon
- name="angle-down"
- :size="12"
- css-classes="caret-down"
- />
+ {{ __('Edit') }}
</button>
<div class="dropdown-menu dropdown-menu-selectable dropdown-open-left">
<ul>
- <template v-if="mergeRequestId">
- <li>
- <a
- href="#"
- @click.prevent="changeMode('mrdiff')"
- :class="{
- 'is-active': viewer === 'mrdiff',
- }"
- >
- <strong class="dropdown-menu-inner-title">
- {{ mergeReviewLine }}
- </strong>
- <span class="dropdown-menu-inner-content">
- {{ __('Compare changes with the merge request target branch') }}
- </span>
- </a>
- </li>
- <li
- role="separator"
- class="divider"
- >
- </li>
- </template>
<li>
<a
href="#"
- @click.prevent="changeMode('editor')"
+ @click.prevent="changeMode($options.viewerTypes.mr)"
:class="{
- 'is-active': viewer === 'editor',
+ 'is-active': viewer === $options.viewerTypes.mr,
}"
>
- <strong class="dropdown-menu-inner-title">{{ __('Editing') }}</strong>
+ <strong class="dropdown-menu-inner-title">
+ {{ mergeReviewLine }}
+ </strong>
<span class="dropdown-menu-inner-content">
- {{ __('View and edit lines') }}
+ {{ __('Compare changes with the merge request target branch') }}
</span>
</a>
</li>
<li>
<a
href="#"
- @click.prevent="changeMode('diff')"
+ @click.prevent="changeMode($options.viewerTypes.diff)"
:class="{
- 'is-active': viewer === 'diff',
+ 'is-active': viewer === $options.viewerTypes.diff,
}"
>
<strong class="dropdown-menu-inner-title">{{ __('Reviewing') }}</strong>
diff --git a/app/assets/javascripts/ide/components/ide_review.vue b/app/assets/javascripts/ide/components/ide_review.vue
index ede1a753f17..0c9ec3b00f0 100644
--- a/app/assets/javascripts/ide/components/ide_review.vue
+++ b/app/assets/javascripts/ide/components/ide_review.vue
@@ -1,25 +1,61 @@
<script>
+import { mapGetters, mapState, mapActions } from 'vuex';
import IdeTreeList from './ide_tree_list.vue';
+import EditorModeDropdown from './editor_mode_dropdown.vue';
+import { viewerTypes } from '../constants';
export default {
components: {
IdeTreeList,
+ EditorModeDropdown,
+ },
+ computed: {
+ ...mapGetters(['currentMergeRequest']),
+ ...mapState(['viewer']),
+ showLatestChangesText() {
+ return !this.currentMergeRequest || this.viewer === viewerTypes.diff;
+ },
+ showMergeRequestText() {
+ return this.currentMergeRequest && this.viewer === viewerTypes.mr;
+ },
+ },
+ mounted() {
+ this.$nextTick(() => {
+ this.updateViewer(this.currentMergeRequest ? viewerTypes.mr : viewerTypes.diff);
+ });
+ },
+ methods: {
+ ...mapActions(['updateViewer']),
},
};
</script>
<template>
<ide-tree-list
- viewer-type="diff"
+ :viewer-type="viewer"
header-class="ide-review-header"
:disable-action-dropdown="true"
>
<template
slot="header"
>
- {{ __('Review') }}
+ <div class="ide-review-button-holder">
+ {{ __('Review') }}
+ <editor-mode-dropdown
+ v-if="currentMergeRequest"
+ :viewer="viewer"
+ :merge-request-id="currentMergeRequest.iid"
+ @click="updateViewer"
+ />
+ </div>
<div class="prepend-top-5 ide-review-sub-header">
- {{ __('Lastest changes') }}
+ <template v-if="showLatestChangesText">
+ {{ __('Latest changes') }}
+ </template>
+ <template v-else-if="showMergeRequestText">
+ {{ __('Merge request') }}
+ (<a :href="currentMergeRequest.web_url">!{{ currentMergeRequest.iid }}</a>)
+ </template>
</div>
</template>
</ide-tree-list>
diff --git a/app/assets/javascripts/ide/components/ide_side_bar.vue b/app/assets/javascripts/ide/components/ide_side_bar.vue
index 3fb9b8b241d..2872d4e8687 100644
--- a/app/assets/javascripts/ide/components/ide_side_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_side_bar.vue
@@ -2,6 +2,7 @@
import { mapState, mapGetters } from 'vuex';
import ProjectAvatarImage from '~/vue_shared/components/project_avatar/image.vue';
import Icon from '~/vue_shared/components/icon.vue';
+import tooltip from '~/vue_shared/directives/tooltip';
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';
@@ -12,6 +13,9 @@ import CommitSection from './repo_commit_section.vue';
import IdeReview from './ide_review.vue';
export default {
+ directives: {
+ tooltip,
+ },
components: {
Icon,
PanelResizer,
@@ -24,9 +28,24 @@ export default {
IdeTree,
IdeReview,
},
+ data() {
+ return {
+ showTooltip: false,
+ };
+ },
computed: {
...mapState(['loading', 'currentBranchId', 'currentActivityView']),
...mapGetters(['currentProject']),
+ branchTooltipTitle() {
+ return this.showTooltip ? this.currentBranchId : undefined;
+ },
+ },
+ watch: {
+ currentBranchId() {
+ this.$nextTick(() => {
+ this.showTooltip = this.$refs.branchId.scrollWidth > this.$refs.branchId.offsetWidth;
+ });
+ },
},
};
</script>
@@ -79,6 +98,9 @@ export default {
</div>
<div
class="sidebar-context-title ide-sidebar-branch-title"
+ ref="branchId"
+ v-tooltip
+ :title="branchTooltipTitle"
>
<icon
name="branch"
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 8a08f9fc7db..ff7e546fb9c 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -3,7 +3,7 @@
import { mapState, mapGetters, mapActions } from 'vuex';
import flash from '~/flash';
import ContentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue';
-import { activityBarViews } from '../constants';
+import { activityBarViews, viewerTypes } from '../constants';
import monacoLoader from '../monaco_loader';
import Editor from '../lib/editor';
import IdeFileButtons from './ide_file_buttons.vue';
@@ -121,7 +121,7 @@ export default {
this.editor.dispose();
this.$nextTick(() => {
- if (this.viewer === 'editor') {
+ if (this.viewer === viewerTypes.edit) {
this.editor.createInstance(this.$refs.editor);
} else {
this.editor.createDiffInstance(this.$refs.editor, !this.isReviewModeActive);
@@ -140,7 +140,7 @@ export default {
this.file.staged && this.file.key.indexOf('unstaged-') === 0 ? head : null,
);
- if (this.viewer === 'mrdiff') {
+ if (this.viewer === viewerTypes.mr) {
this.editor.attachMergeRequestModel(this.model);
} else {
this.editor.attachModel(this.model);
@@ -181,6 +181,7 @@ export default {
});
},
},
+ viewerTypes,
};
</script>
@@ -199,7 +200,7 @@ export default {
href="javascript:void(0);"
role="button"
@click.prevent="setFileViewMode({ file, viewMode: 'edit' })">
- <template v-if="viewer === 'editor'">
+ <template v-if="viewer === $options.viewerTypes.edit">
{{ __('Edit') }}
</template>
<template v-else>
diff --git a/app/assets/javascripts/ide/constants.js b/app/assets/javascripts/ide/constants.js
index 16110b2f5a4..86c5f0c4421 100644
--- a/app/assets/javascripts/ide/constants.js
+++ b/app/assets/javascripts/ide/constants.js
@@ -12,3 +12,9 @@ export const activityBarViews = {
commit: 'commit-section',
review: 'ide-review',
};
+
+export const viewerTypes = {
+ mr: 'mrdiff',
+ edit: 'editor',
+ diff: 'diff',
+};
diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js
index ee30e5074b3..adca85dc65b 100644
--- a/app/assets/javascripts/ide/ide_router.js
+++ b/app/assets/javascripts/ide/ide_router.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import VueRouter from 'vue-router';
import flash from '~/flash';
import store from './stores';
+import { activityBarViews } from './constants';
Vue.use(VueRouter);
@@ -101,14 +102,14 @@ router.beforeEach((to, from, next) => {
throw e;
});
} else if (to.params.mrid) {
- store.dispatch('updateViewer', 'mrdiff');
-
store
.dispatch('getMergeRequestData', {
projectId: fullProjectId,
mergeRequestId: to.params.mrid,
})
.then(mr => {
+ store.dispatch('updateActivityBarView', activityBarViews.review);
+
store.dispatch('getBranchData', {
projectId: fullProjectId,
branchId: mr.source_branch,
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index 4fe6f5334e3..8076de1b7e3 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -5,6 +5,7 @@ import service from '../../services';
import * as types from '../mutation_types';
import router from '../../ide_router';
import { setPageTitle } from '../utils';
+import { viewerTypes } from '../../constants';
export const closeFile = ({ commit, state, dispatch }, file) => {
const path = file.path;
@@ -23,7 +24,7 @@ export const closeFile = ({ commit, state, dispatch }, file) => {
const nextFileToOpen = state.openFiles[nextIndexToOpen];
if (nextFileToOpen.pending) {
- dispatch('updateViewer', 'diff');
+ dispatch('updateViewer', viewerTypes.diff);
dispatch('openPendingTab', {
file: nextFileToOpen,
keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged',
@@ -194,7 +195,11 @@ export const unstageChange = ({ commit }, path) => {
};
export const openPendingTab = ({ commit, getters, dispatch, state }, { file, keyPrefix }) => {
- if (getters.activeFile && getters.activeFile.path === file.path && state.viewer === 'diff') {
+ if (
+ getters.activeFile &&
+ getters.activeFile.path === file.path &&
+ state.viewer === viewerTypes.diff
+ ) {
return false;
}
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index fd31fcd14ab..e7411f16a4f 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -1,4 +1,4 @@
-import { activityBarViews } from '../constants';
+import { activityBarViews, viewerTypes } from '../constants';
export default () => ({
currentProjectId: '',
@@ -18,7 +18,7 @@ export default () => ({
rightPanelCollapsed: false,
panelResizing: false,
entries: {},
- viewer: 'editor',
+ viewer: viewerTypes.edit,
delayViewerUpdated: false,
currentActivityView: activityBarViews.edit,
unusedSeal: true,
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 9c374cda3f3..d3330cda8c6 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -972,6 +972,14 @@
.ide-review-header {
flex-direction: column;
align-items: flex-start;
+
+ .dropdown {
+ margin-left: auto;
+ }
+
+ a {
+ color: $gl-link-color;
+ }
}
.ide-review-sub-header {
@@ -987,3 +995,23 @@
.ide-new-modal-label {
line-height: 34px;
}
+
+.ide-review-button-holder {
+ display: flex;
+ width: 100%;
+ align-items: center;
+}
+
+.ide-context-header {
+ .avatar {
+ flex: 0 0 40px;
+ }
+}
+
+.ide-sidebar-project-title {
+ min-width: 0;
+
+ .sidebar-context-title {
+ white-space: nowrap;
+ }
+}
diff --git a/spec/javascripts/ide/components/ide_review_spec.js b/spec/javascripts/ide/components/ide_review_spec.js
index 13753c6b6fb..b9ee22b7c1a 100644
--- a/spec/javascripts/ide/components/ide_review_spec.js
+++ b/spec/javascripts/ide/components/ide_review_spec.js
@@ -2,6 +2,7 @@ import Vue from 'vue';
import IdeReview from '~/ide/components/ide_review.vue';
import store from '~/ide/stores';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
+import { trimText } from '../../helpers/vue_component_helper';
import { resetStore, file } from '../helpers';
import { projectData } from '../mock_data';
@@ -30,4 +31,39 @@ describe('IDE review mode', () => {
it('renders list of files', () => {
expect(vm.$el.textContent).toContain('fileName');
});
+
+ describe('merge request', () => {
+ beforeEach(done => {
+ store.state.currentMergeRequestId = '1';
+ store.state.projects.abcproject.mergeRequests['1'] = {
+ iid: 123,
+ web_url: 'testing123',
+ };
+
+ vm.$nextTick(done);
+ });
+
+ it('renders edit dropdown', () => {
+ expect(vm.$el.querySelector('.btn')).not.toBe(null);
+ });
+
+ it('renders merge request link & IID', () => {
+ const link = vm.$el.querySelector('.ide-review-sub-header');
+
+ expect(link.querySelector('a').getAttribute('href')).toBe('testing123');
+ expect(trimText(link.textContent)).toBe('Merge request (!123)');
+ });
+
+ it('changes text to latest changes when viewer is not mrdiff', done => {
+ store.state.viewer = 'diff';
+
+ vm.$nextTick(() => {
+ expect(trimText(vm.$el.querySelector('.ide-review-sub-header').textContent)).toBe(
+ 'Latest changes',
+ );
+
+ done();
+ });
+ });
+ });
});
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index c8206778639..3c6d75ab5e4 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -11,4 +11,5 @@ export const projectData = {
treeId: 'abcproject/master',
},
},
+ mergeRequests: {},
};