summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Slaughter <pslaughter@gitlab.com>2019-04-04 13:55:49 -0500
committerPaul Slaughter <pslaughter@gitlab.com>2019-04-04 15:35:45 -0500
commitc1a097e1cee43b127de17d769546ffa244cbf484 (patch)
treedac9796a9f7a325407d47f1e2fe2e7966ae6a678
parent9deaa79c5eb42618756288d85c8ad2c757e0589f (diff)
downloadgitlab-ce-60021-fix-ide-file-dropdown.tar.gz
Refactor new_dropdown/index to receive isOpen prop60021-fix-ide-file-dropdown
**Why?** Previously it managed this as an internal data property, but there was extra complexity involved because the component doesn't have all the information it needs (i.e. the `mouseOver` prop). This is a good opportunity to colocate the data prop with the component that has the information to change it (i.e. `file_row`) and let `new_dropdown/index` receive this value as a prop.
-rw-r--r--app/assets/javascripts/ide/components/file_row_extra.vue5
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/index.vue23
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue12
-rw-r--r--spec/javascripts/ide/components/file_row_extra_spec.js2
-rw-r--r--spec/javascripts/ide/components/new_dropdown/index_spec.js4
-rw-r--r--spec/javascripts/vue_shared/components/file_row_spec.js60
6 files changed, 79 insertions, 27 deletions
diff --git a/app/assets/javascripts/ide/components/file_row_extra.vue b/app/assets/javascripts/ide/components/file_row_extra.vue
index d6673cf0421..80a6ab9598a 100644
--- a/app/assets/javascripts/ide/components/file_row_extra.vue
+++ b/app/assets/javascripts/ide/components/file_row_extra.vue
@@ -23,7 +23,7 @@ export default {
type: Object,
required: true,
},
- mouseOver: {
+ dropdownOpen: {
type: Boolean,
required: true,
},
@@ -92,8 +92,9 @@ export default {
<new-dropdown
:type="file.type"
:path="file.path"
- :mouse-over="mouseOver"
+ :is-open="dropdownOpen"
class="prepend-left-8"
+ v-on="$listeners"
/>
</div>
</template>
diff --git a/app/assets/javascripts/ide/components/new_dropdown/index.vue b/app/assets/javascripts/ide/components/new_dropdown/index.vue
index 593a9162a06..27d24fa5e1d 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/index.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/index.vue
@@ -21,38 +21,29 @@ export default {
required: false,
default: '',
},
- mouseOver: {
+ isOpen: {
type: Boolean,
- required: true,
+ required: false,
+ default: false,
},
},
- data() {
- return {
- dropdownOpen: false,
- };
- },
watch: {
- dropdownOpen() {
+ isOpen() {
this.$nextTick(() => {
this.$refs.dropdownMenu.scrollIntoView({
block: 'nearest',
});
});
},
- mouseOver() {
- if (!this.mouseOver) {
- this.dropdownOpen = false;
- }
- },
},
methods: {
...mapActions(['createTempEntry', 'openNewEntryModal', 'deleteEntry']),
createNewItem(type) {
this.openNewEntryModal({ type, path: this.path });
- this.dropdownOpen = false;
+ this.$emit('toggle', false);
},
openDropdown() {
- this.dropdownOpen = !this.dropdownOpen;
+ this.$emit('toggle', !this.isOpen);
},
},
modalTypes,
@@ -63,7 +54,7 @@ export default {
<div class="ide-new-btn">
<div
:class="{
- show: dropdownOpen,
+ show: isOpen,
}"
class="dropdown d-flex"
>
diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue
index 7096c1f4518..1bfa91500cb 100644
--- a/app/assets/javascripts/vue_shared/components/file_row.vue
+++ b/app/assets/javascripts/vue_shared/components/file_row.vue
@@ -39,7 +39,7 @@ export default {
},
data() {
return {
- mouseOver: false,
+ dropdownOpen: false,
};
},
computed: {
@@ -123,8 +123,8 @@ export default {
return this.$router.currentRoute.path === `/project${this.file.url}`;
},
- toggleHover(over) {
- this.mouseOver = over;
+ toggleDropdown(val) {
+ this.dropdownOpen = val;
},
},
};
@@ -140,8 +140,7 @@ export default {
class="file-row"
role="button"
@click="clickFile"
- @mouseover="toggleHover(true)"
- @mouseleave="toggleHover(false)"
+ @mouseleave="toggleDropdown(false)"
>
<div class="file-row-name-container">
<span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated">
@@ -160,7 +159,8 @@ export default {
:is="extraComponent"
v-if="extraComponent && !(hideExtraOnTree && file.type === 'tree')"
:file="file"
- :mouse-over="mouseOver"
+ :dropdown-open="dropdownOpen"
+ @toggle="toggleDropdown($event)"
/>
</div>
</div>
diff --git a/spec/javascripts/ide/components/file_row_extra_spec.js b/spec/javascripts/ide/components/file_row_extra_spec.js
index c93a939ad71..d7fed3f0681 100644
--- a/spec/javascripts/ide/components/file_row_extra_spec.js
+++ b/spec/javascripts/ide/components/file_row_extra_spec.js
@@ -20,7 +20,7 @@ describe('IDE extra file row component', () => {
file: {
...file('test'),
},
- mouseOver: false,
+ dropdownOpen: false,
});
spyOnProperty(vm, 'getUnstagedFilesCountForPath').and.returnValue(() => unstagedFilesCount);
diff --git a/spec/javascripts/ide/components/new_dropdown/index_spec.js b/spec/javascripts/ide/components/new_dropdown/index_spec.js
index 83e530f0a6a..aaebe88f314 100644
--- a/spec/javascripts/ide/components/new_dropdown/index_spec.js
+++ b/spec/javascripts/ide/components/new_dropdown/index_spec.js
@@ -56,11 +56,11 @@ describe('new dropdown component', () => {
});
});
- describe('dropdownOpen', () => {
+ describe('isOpen', () => {
it('scrolls dropdown into view', done => {
spyOn(vm.$refs.dropdownMenu, 'scrollIntoView');
- vm.dropdownOpen = true;
+ vm.isOpen = true;
setTimeout(() => {
expect(vm.$refs.dropdownMenu.scrollIntoView).toHaveBeenCalledWith({
diff --git a/spec/javascripts/vue_shared/components/file_row_spec.js b/spec/javascripts/vue_shared/components/file_row_spec.js
index d1fd899c1a8..7da69e3fa84 100644
--- a/spec/javascripts/vue_shared/components/file_row_spec.js
+++ b/spec/javascripts/vue_shared/components/file_row_spec.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import FileRow from '~/vue_shared/components/file_row.vue';
+import FileRowExtra from '~/ide/components/file_row_extra.vue';
import { file } from 'spec/ide/helpers';
import mountComponent from '../../helpers/vue_mount_component_helper';
@@ -16,6 +17,10 @@ describe('File row component', () => {
vm.$destroy();
});
+ const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown');
+ const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button');
+ const findFileRow = () => vm.$el.querySelector('.file-row');
+
it('renders name', () => {
createComponent({
file: file('t4'),
@@ -84,4 +89,59 @@ describe('File row component', () => {
expect(vm.$el.querySelector('.js-file-row-header')).not.toBe(null);
});
+
+ describe('new dropdown', () => {
+ beforeEach(() => {
+ createComponent({
+ file: file('t5'),
+ level: 1,
+ extraComponent: FileRowExtra,
+ });
+ });
+
+ it('renders in extra component', () => {
+ expect(findNewDropdown()).not.toBe(null);
+ });
+
+ it('is hidden at start', () => {
+ expect(findNewDropdown()).not.toHaveClass('show');
+ });
+
+ it('is opened when button is clicked', done => {
+ expect(vm.dropdownOpen).toBe(false);
+ findNewDropdownButton().dispatchEvent(new Event('click'));
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.dropdownOpen).toBe(true);
+ expect(findNewDropdown()).toHaveClass('show');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ describe('when opened', () => {
+ beforeEach(() => {
+ vm.dropdownOpen = true;
+ });
+
+ it('stays open when button triggers mouseout', () => {
+ findNewDropdownButton().dispatchEvent(new Event('mouseout'));
+
+ expect(vm.dropdownOpen).toBe(true);
+ });
+
+ it('stays open when button triggers mouseleave', () => {
+ findNewDropdownButton().dispatchEvent(new Event('mouseleave'));
+
+ expect(vm.dropdownOpen).toBe(true);
+ });
+
+ it('closes when row triggers mouseleave', () => {
+ findFileRow().dispatchEvent(new Event('mouseleave'));
+
+ expect(vm.dropdownOpen).toBe(false);
+ });
+ });
+ });
});