summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Zallmann <tzallmann@gitlab.com>2018-01-04 09:31:06 +0000
committerFilipa Lacerda <filipa@gitlab.com>2018-01-04 09:31:06 +0000
commit7fbb5addaf7c15c971f584ebeecb2c93773093c0 (patch)
tree1fdbd80a4d6b3b660a329751c693ab3e449aca54
parent0e7e9e32b30bd3c310a769eaef91843b609697df (diff)
downloadgitlab-ce-7fbb5addaf7c15c971f584ebeecb2c93773093c0.tar.gz
Resolve "Resizable file list and commit panel"
-rw-r--r--app/assets/javascripts/ide/components/ide_context_bar.vue33
-rw-r--r--app/assets/javascripts/ide/components/ide_side_bar.vue33
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue6
-rw-r--r--app/assets/javascripts/ide/stores/actions.js4
-rw-r--r--app/assets/javascripts/ide/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js5
-rw-r--r--app/assets/javascripts/ide/stores/state.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/panel_resizer.vue91
-rw-r--r--app/assets/stylesheets/pages/repo.scss34
-rw-r--r--spec/javascripts/vue_shared/components/panel_resizer_spec.js59
10 files changed, 262 insertions, 5 deletions
diff --git a/app/assets/javascripts/ide/components/ide_context_bar.vue b/app/assets/javascripts/ide/components/ide_context_bar.vue
index 5a08718e386..78c01272af6 100644
--- a/app/assets/javascripts/ide/components/ide_context_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_context_bar.vue
@@ -2,11 +2,18 @@
import { mapGetters, mapState, mapActions } from 'vuex';
import repoCommitSection from './repo_commit_section.vue';
import icon from '../../vue_shared/components/icon.vue';
+import panelResizer from '../../vue_shared/components/panel_resizer.vue';
export default {
+ data() {
+ return {
+ width: 290,
+ };
+ },
components: {
repoCommitSection,
icon,
+ panelResizer,
},
computed: {
...mapState([
@@ -18,10 +25,20 @@ export default {
currentIcon() {
return this.rightPanelCollapsed ? 'angle-double-left' : 'angle-double-right';
},
+ maxSize() {
+ return window.innerWidth / 2;
+ },
+ panelStyle() {
+ if (!this.rightPanelCollapsed) {
+ return { width: `${this.width}px` };
+ }
+ return {};
+ },
},
methods: {
...mapActions([
'setPanelCollapsedStatus',
+ 'setResizingStatus',
]),
toggleCollapsed() {
this.setPanelCollapsedStatus({
@@ -29,6 +46,12 @@ export default {
collapsed: !this.rightPanelCollapsed,
});
},
+ resizingStarted() {
+ this.setResizingStatus(true);
+ },
+ resizingEnded() {
+ this.setResizingStatus(false);
+ },
},
};
</script>
@@ -39,6 +62,7 @@ export default {
:class="{
'is-collapsed': rightPanelCollapsed,
}"
+ :style="panelStyle"
>
<div
class="multi-file-commit-panel-section">
@@ -71,5 +95,14 @@ export default {
<repo-commit-section
class=""/>
</div>
+ <panel-resizer
+ :size.sync="width"
+ :enabled="!rightPanelCollapsed"
+ :start-size="290"
+ :min-size="200"
+ :max-size="maxSize"
+ @resize-start="resizingStarted"
+ @resize-end="resizingEnded"
+ side="left"/>
</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 535398d98c2..269f300a04d 100644
--- a/app/assets/javascripts/ide/components/ide_side_bar.vue
+++ b/app/assets/javascripts/ide/components/ide_side_bar.vue
@@ -2,11 +2,18 @@
import { mapState, mapActions } from 'vuex';
import projectTree from './ide_project_tree.vue';
import icon from '../../vue_shared/components/icon.vue';
+import panelResizer from '../../vue_shared/components/panel_resizer.vue';
export default {
+ data() {
+ return {
+ width: 290,
+ };
+ },
components: {
projectTree,
icon,
+ panelResizer,
},
computed: {
...mapState([
@@ -16,10 +23,20 @@ export default {
currentIcon() {
return this.leftPanelCollapsed ? 'angle-double-right' : 'angle-double-left';
},
+ maxSize() {
+ return window.innerWidth / 2;
+ },
+ panelStyle() {
+ if (!this.leftPanelCollapsed) {
+ return { width: `${this.width}px` };
+ }
+ return {};
+ },
},
methods: {
...mapActions([
'setPanelCollapsedStatus',
+ 'setResizingStatus',
]),
toggleCollapsed() {
this.setPanelCollapsedStatus({
@@ -27,6 +44,12 @@ export default {
collapsed: !this.leftPanelCollapsed,
});
},
+ resizingStarted() {
+ this.setResizingStatus(true);
+ },
+ resizingEnded() {
+ this.setResizingStatus(false);
+ },
},
};
</script>
@@ -37,6 +60,7 @@ export default {
:class="{
'is-collapsed': leftPanelCollapsed,
}"
+ :style="panelStyle"
>
<div class="multi-file-commit-panel-inner">
<project-tree
@@ -58,5 +82,14 @@ export default {
class="collapse-text"
>Collapse sidebar</span>
</button>
+ <panel-resizer
+ :size.sync="width"
+ :enabled="!leftPanelCollapsed"
+ :start-size="290"
+ :min-size="200"
+ :max-size="maxSize"
+ @resize-start="resizingStarted"
+ @resize-end="resizingEnded"
+ side="right"/>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index 221be4b9074..343fd0a5300 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -90,6 +90,11 @@ export default {
rightPanelCollapsed() {
this.editor.updateDimensions();
},
+ panelResizing(isResizing) {
+ if (isResizing === false) {
+ this.editor.updateDimensions();
+ }
+ },
},
computed: {
...mapGetters([
@@ -99,6 +104,7 @@ export default {
...mapState([
'leftPanelCollapsed',
'rightPanelCollapsed',
+ 'panelResizing',
]),
shouldHideEditor() {
return this.activeFile.binary && !this.activeFile.raw;
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index c01046c8c76..335882bb6d7 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -63,6 +63,10 @@ export const setPanelCollapsedStatus = ({ commit }, { side, collapsed }) => {
}
};
+export const setResizingStatus = ({ commit }, resizing) => {
+ commit(types.SET_RESIZING_STATUS, resizing);
+};
+
export const checkCommitStatus = ({ state }) =>
service
.getBranchData(state.currentProjectId, state.currentBranchId)
diff --git a/app/assets/javascripts/ide/stores/mutation_types.js b/app/assets/javascripts/ide/stores/mutation_types.js
index 4e3c10972ba..69b218a5e7d 100644
--- a/app/assets/javascripts/ide/stores/mutation_types.js
+++ b/app/assets/javascripts/ide/stores/mutation_types.js
@@ -5,6 +5,7 @@ export const SET_ROOT = 'SET_ROOT';
export const SET_LAST_COMMIT_DATA = 'SET_LAST_COMMIT_DATA';
export const SET_LEFT_PANEL_COLLAPSED = 'SET_LEFT_PANEL_COLLAPSED';
export const SET_RIGHT_PANEL_COLLAPSED = 'SET_RIGHT_PANEL_COLLAPSED';
+export const SET_RESIZING_STATUS = 'SET_RESIZING_STATUS';
// Project Mutation Types
export const SET_PROJECT = 'SET_PROJECT';
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 2fed9019cb6..03d81be10a1 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -49,6 +49,11 @@ export default {
rightPanelCollapsed: collapsed,
});
},
+ [types.SET_RESIZING_STATUS](state, resizing) {
+ Object.assign(state, {
+ panelResizing: resizing,
+ });
+ },
[types.SET_LAST_COMMIT_DATA](state, { entry, lastCommit }) {
Object.assign(entry.lastCommit, {
id: lastCommit.commit.id,
diff --git a/app/assets/javascripts/ide/stores/state.js b/app/assets/javascripts/ide/stores/state.js
index 539e382830f..61d12096946 100644
--- a/app/assets/javascripts/ide/stores/state.js
+++ b/app/assets/javascripts/ide/stores/state.js
@@ -19,4 +19,5 @@ export default () => ({
projects: {},
leftPanelCollapsed: false,
rightPanelCollapsed: true,
+ panelResizing: false,
});
diff --git a/app/assets/javascripts/vue_shared/components/panel_resizer.vue b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
new file mode 100644
index 00000000000..4371534d345
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/panel_resizer.vue
@@ -0,0 +1,91 @@
+<script>
+export default {
+ props: {
+ startSize: {
+ type: Number,
+ required: true,
+ },
+ side: {
+ type: String,
+ required: true,
+ },
+ minSize: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ maxSize: {
+ type: Number,
+ required: false,
+ default: Number.MAX_VALUE,
+ },
+ enabled: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ },
+ data() {
+ return {
+ size: this.startSize,
+ };
+ },
+ computed: {
+ className() {
+ return `drag${this.side}`;
+ },
+ cursorStyle() {
+ if (this.enabled) {
+ return { cursor: 'ew-resize' };
+ }
+ return {};
+ },
+ },
+ methods: {
+ resetSize(e) {
+ e.preventDefault();
+ this.size = this.startSize;
+ this.$emit('update:size', this.size);
+ },
+ startDrag(e) {
+ if (this.enabled) {
+ e.preventDefault();
+ this.startPos = e.clientX;
+ this.currentStartSize = this.size;
+ document.addEventListener('mousemove', this.drag);
+ document.addEventListener('mouseup', this.endDrag, { once: true });
+ this.$emit('resize-start', this.size);
+ }
+ },
+ drag(e) {
+ e.preventDefault();
+ let moved = e.clientX - this.startPos;
+ if (this.side === 'left') moved = -moved;
+ let newSize = this.currentStartSize + moved;
+ if (newSize < this.minSize) {
+ newSize = this.minSize;
+ } else if (newSize > this.maxSize) {
+ newSize = this.maxSize;
+ }
+ this.size = newSize;
+
+ this.$emit('update:size', newSize);
+ },
+ endDrag(e) {
+ e.preventDefault();
+ document.removeEventListener('mousemove', this.drag);
+ this.$emit('resize-end', this.size);
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ class="dragHandle"
+ :class="className"
+ :style="cursorStyle"
+ @mousedown="startDrag"
+ @dblclick="resetSize"
+ ></div>
+</template>
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 51cc1729d9a..d01cbadebcc 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -36,10 +36,6 @@
}
}
-.with-performance-bar .ide-view {
- height: calc(100vh - #{$header-height});
-}
-
.ide-file-list {
flex: 1;
@@ -242,12 +238,13 @@ table.table tr td.multi-file-table-name {
.multi-file-commit-panel {
display: flex;
+ position: relative;
flex-direction: column;
height: 100%;
width: 290px;
padding: 0;
background-color: $gray-light;
- border-left: 1px solid $white-dark;
+ padding-right: 3px;
.projects-sidebar {
display: flex;
@@ -496,3 +493,30 @@ table.table tr td.multi-file-table-name {
margin-top: $header-height;
margin-bottom: 0;
}
+
+.with-performance-bar {
+ .ide-flash-container.flash-container {
+ margin-top: $header-height + $performance-bar-height;
+ }
+
+ .ide-view {
+ height: calc(100vh - #{$header-height + $performance-bar-height});
+ }
+}
+
+
+.dragHandle {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 3px;
+ background-color: $white-dark;
+
+ &.dragright {
+ right: 0;
+ }
+
+ &.dragleft {
+ left: 0;
+ }
+}
diff --git a/spec/javascripts/vue_shared/components/panel_resizer_spec.js b/spec/javascripts/vue_shared/components/panel_resizer_spec.js
new file mode 100644
index 00000000000..70ce3dffaba
--- /dev/null
+++ b/spec/javascripts/vue_shared/components/panel_resizer_spec.js
@@ -0,0 +1,59 @@
+import Vue from 'vue';
+import panelResizer from '~/vue_shared/components/panel_resizer.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
+
+describe('Panel Resizer component', () => {
+ let vm;
+ let PanelResizer;
+
+ const triggerEvent = (eventName, el = vm.$el, clientX = 0) => {
+ const event = document.createEvent('MouseEvents');
+ event.initMouseEvent(eventName, true, true, window, 1, clientX, 0, clientX, 0, false, false,
+ false, false, 0, null);
+
+ el.dispatchEvent(event);
+ };
+
+ beforeEach(() => {
+ PanelResizer = Vue.extend(panelResizer);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('should render a div element with the correct classes and styles', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'left',
+ });
+
+ expect(vm.$el.tagName).toEqual('DIV');
+ expect(vm.$el.getAttribute('class')).toBe('dragHandle dragleft');
+ expect(vm.$el.getAttribute('style')).toBe('cursor: ew-resize;');
+ });
+
+ it('should render a div element with the correct classes for a right side panel', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'right',
+ });
+
+ expect(vm.$el.tagName).toEqual('DIV');
+ expect(vm.$el.getAttribute('class')).toBe('dragHandle dragright');
+ });
+
+ it('drag the resizer', () => {
+ vm = mountComponent(PanelResizer, {
+ startSize: 100,
+ side: 'left',
+ });
+
+ spyOn(vm, '$emit');
+ triggerEvent('mousedown', vm.$el);
+ triggerEvent('mousemove', document);
+ triggerEvent('mouseup', document);
+ expect(vm.$emit.calls.allArgs()).toEqual([['resize-start', 100], ['update:size', 100], ['resize-end', 100]]);
+ expect(vm.size).toBe(100);
+ });
+});