Merge branch 'ide-row-dropdown-design-update' into 'master'

Improvements to new entry dropdowns in Web IDE

Closes #44845

See merge request gitlab-org/gitlab-ce!20526
This commit is contained in:
Filipa Lacerda 2018-07-12 08:42:27 +00:00
commit d2c5ac61cd
22 changed files with 363 additions and 253 deletions

View file

@ -1,6 +1,7 @@
<script> <script>
import Mousetrap from 'mousetrap'; import Mousetrap from 'mousetrap';
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import NewModal from './new_dropdown/modal.vue';
import IdeSidebar from './ide_side_bar.vue'; import IdeSidebar from './ide_side_bar.vue';
import RepoTabs from './repo_tabs.vue'; import RepoTabs from './repo_tabs.vue';
import IdeStatusBar from './ide_status_bar.vue'; import IdeStatusBar from './ide_status_bar.vue';
@ -13,6 +14,7 @@ const originalStopCallback = Mousetrap.stopCallback;
export default { export default {
components: { components: {
NewModal,
IdeSidebar, IdeSidebar,
RepoTabs, RepoTabs,
IdeStatusBar, IdeStatusBar,
@ -137,5 +139,6 @@ export default {
/> />
</div> </div>
<ide-status-bar :file="activeFile"/> <ide-status-bar :file="activeFile"/>
<new-modal />
</article> </article>
</template> </template>

View file

@ -1,12 +1,16 @@
<script> <script>
import { mapState, mapGetters, mapActions } from 'vuex'; import { mapState, mapGetters, mapActions } from 'vuex';
import NewDropdown from './new_dropdown/index.vue'; import Icon from '~/vue_shared/components/icon.vue';
import IdeTreeList from './ide_tree_list.vue'; import IdeTreeList from './ide_tree_list.vue';
import Upload from './new_dropdown/upload.vue';
import NewEntryButton from './new_dropdown/button.vue';
export default { export default {
components: { components: {
NewDropdown, Icon,
Upload,
IdeTreeList, IdeTreeList,
NewEntryButton,
}, },
computed: { computed: {
...mapState(['currentBranchId']), ...mapState(['currentBranchId']),
@ -20,23 +24,42 @@ export default {
} }
}, },
methods: { methods: {
...mapActions(['updateViewer']), ...mapActions(['updateViewer', 'openNewEntryModal', 'createTempEntry']),
}, },
}; };
</script> </script>
<template> <template>
<ide-tree-list <ide-tree-list
header-class="d-flex w-100"
viewer-type="editor" viewer-type="editor"
> >
<template <template
slot="header" slot="header"
> >
{{ __('Edit') }} {{ __('Edit') }}
<new-dropdown <div class="ml-auto d-flex">
:project-id="currentProject.name_with_namespace" <new-entry-button
:branch="currentBranchId" :label="__('New file')"
/> :show-label="false"
class="d-flex border-0 p-0 mr-3"
icon="doc-new"
@click="openNewEntryModal({ type: 'blob' })"
/>
<upload
:show-label="false"
class="d-flex mr-3"
button-css-classes="border-0 p-0"
@create="createTempEntry"
/>
<new-entry-button
:label="__('New directory')"
:show-label="false"
class="d-flex border-0 p-0"
icon="folder-new"
@click="openNewEntryModal({ type: 'tree' })"
/>
</div>
</template> </template>
</ide-tree-list> </ide-tree-list>
</template> </template>

View file

@ -0,0 +1,51 @@
<script>
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
Icon,
},
props: {
label: {
type: String,
required: false,
default: null,
},
icon: {
type: String,
required: true,
},
iconClasses: {
type: String,
required: false,
default: null,
},
showLabel: {
type: Boolean,
required: false,
default: true,
},
},
methods: {
clicked() {
this.$emit('click');
},
},
};
</script>
<template>
<button
:aria-label="label"
type="button"
@click.stop.prevent="clicked"
>
<icon
:name="icon"
:css-classes="iconClasses"
/>
<template v-if="showLabel">
{{ label }}
</template>
</button>
</template>

View file

@ -3,12 +3,14 @@ import { mapActions } from 'vuex';
import icon from '~/vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import newModal from './modal.vue'; import newModal from './modal.vue';
import upload from './upload.vue'; import upload from './upload.vue';
import ItemButton from './button.vue';
export default { export default {
components: { components: {
icon, icon,
newModal, newModal,
upload, upload,
ItemButton,
}, },
props: { props: {
branch: { branch: {
@ -20,11 +22,13 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
mouseOver: {
type: Boolean,
required: true,
},
}, },
data() { data() {
return { return {
openModal: false,
modalType: '',
dropdownOpen: false, dropdownOpen: false,
}; };
}, },
@ -34,17 +38,18 @@ export default {
this.$refs.dropdownMenu.scrollIntoView(); this.$refs.dropdownMenu.scrollIntoView();
}); });
}, },
mouseOver() {
if (!this.mouseOver) {
this.dropdownOpen = false;
}
},
}, },
methods: { methods: {
...mapActions(['createTempEntry']), ...mapActions(['createTempEntry', 'openNewEntryModal']),
createNewItem(type) { createNewItem(type) {
this.modalType = type; this.openNewEntryModal({ type, path: this.path });
this.openModal = true;
this.dropdownOpen = false; this.dropdownOpen = false;
}, },
hideModal() {
this.openModal = false;
},
openDropdown() { openDropdown() {
this.dropdownOpen = !this.dropdownOpen; this.dropdownOpen = !this.dropdownOpen;
}, },
@ -58,23 +63,19 @@ export default {
:class="{ :class="{
show: dropdownOpen, show: dropdownOpen,
}" }"
class="dropdown" class="dropdown d-flex"
> >
<button <button
:aria-label="__('Create new file or directory')"
type="button" type="button"
class="btn btn-sm btn-default dropdown-toggle add-to-tree" class="rounded border-0 d-flex ide-entry-dropdown-toggle"
aria-label="Create new file or directory"
@click.stop="openDropdown()" @click.stop="openDropdown()"
> >
<icon <icon
:size="12" name="hamburger"
name="plus"
css-classes="float-left"
/> />
<icon <icon
:size="12"
name="arrow-down" name="arrow-down"
css-classes="float-left"
/> />
</button> </button>
<ul <ul
@ -82,39 +83,30 @@ export default {
class="dropdown-menu dropdown-menu-right" class="dropdown-menu dropdown-menu-right"
> >
<li> <li>
<a <item-button
href="#" :label="__('New file')"
role="button" class="d-flex"
@click.stop.prevent="createNewItem('blob')" icon="doc-new"
> icon-classes="mr-2"
{{ __('New file') }} @click="createNewItem('blob')"
</a> />
</li> </li>
<li> <li>
<upload <upload
:branch-id="branch"
:path="path" :path="path"
@create="createTempEntry" @create="createTempEntry"
/> />
</li> </li>
<li> <li>
<a <item-button
href="#" :label="__('New directory')"
role="button" class="d-flex"
@click.stop.prevent="createNewItem('tree')" icon="folder-new"
> icon-classes="mr-2"
{{ __('New directory') }} @click="createNewItem('tree')"
</a> />
</li> </li>
</ul> </ul>
</div> </div>
<new-modal
v-if="openModal"
:type="modalType"
:branch-id="branch"
:path="path"
@hide="hideModal"
@create="createTempEntry"
/>
</div> </div>
</template> </template>

View file

@ -1,78 +1,70 @@
<script> <script>
import { __ } from '~/locale'; import { __ } from '~/locale';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; import { mapActions, mapState } from 'vuex';
import GlModal from '~/vue_shared/components/gl_modal.vue';
export default { export default {
components: { components: {
DeprecatedModal, GlModal,
},
props: {
branchId: {
type: String,
required: true,
},
type: {
type: String,
required: true,
},
path: {
type: String,
required: true,
},
}, },
data() { data() {
return { return {
entryName: this.path !== '' ? `${this.path}/` : '', name: '',
}; };
}, },
computed: { computed: {
...mapState(['newEntryModal']),
entryName: {
get() {
return this.name || (this.newEntryModal.path !== '' ? `${this.newEntryModal.path}/` : '');
},
set(val) {
this.name = val;
},
},
modalTitle() { modalTitle() {
if (this.type === 'tree') { if (this.newEntryModal.type === 'tree') {
return __('Create new directory'); return __('Create new directory');
} }
return __('Create new file'); return __('Create new file');
}, },
buttonLabel() { buttonLabel() {
if (this.type === 'tree') { if (this.newEntryModal.type === 'tree') {
return __('Create directory'); return __('Create directory');
} }
return __('Create file'); return __('Create file');
}, },
}, },
mounted() {
this.$refs.fieldName.focus();
},
methods: { methods: {
...mapActions(['createTempEntry']),
createEntryInStore() { createEntryInStore() {
this.$emit('create', { this.createTempEntry({
branchId: this.branchId, name: this.name,
name: this.entryName, type: this.newEntryModal.type,
type: this.type,
}); });
this.hideModal();
}, },
hideModal() { focusInput() {
this.$emit('hide'); setTimeout(() => {
this.$refs.fieldName.focus();
});
}, },
}, },
}; };
</script> </script>
<template> <template>
<deprecated-modal <gl-modal
:title="modalTitle" id="ide-new-entry"
:primary-button-label="buttonLabel" :header-title-text="modalTitle"
kind="success" :footer-primary-button-text="buttonLabel"
@cancel="hideModal" footer-primary-button-variant="success"
@submit="createEntryInStore" @submit="createEntryInStore"
@open="focusInput"
> >
<form <div
slot="body"
class="form-group row" class="form-group row"
@submit.prevent="createEntryInStore"
> >
<label class="label-light col-form-label col-sm-3"> <label class="label-light col-form-label col-sm-3">
{{ __('Name') }} {{ __('Name') }}
@ -85,6 +77,6 @@ export default {
class="form-control" class="form-control"
/> />
</div> </div>
</form> </div>
</deprecated-modal> </gl-modal>
</template> </template>

View file

@ -1,71 +1,85 @@
<script> <script>
export default { import Icon from '~/vue_shared/components/icon.vue';
props: { import ItemButton from './button.vue';
branchId: {
type: String,
required: true,
},
path: {
type: String,
required: false,
default: '',
},
},
mounted() {
this.$refs.fileUpload.addEventListener('change', this.openFile);
},
beforeDestroy() {
this.$refs.fileUpload.removeEventListener('change', this.openFile);
},
methods: {
createFile(target, file, isText) {
const { name } = file;
let { result } = target;
if (!isText) { export default {
// eslint-disable-next-line prefer-destructuring components: {
result = result.split('base64,')[1]; Icon,
} ItemButton,
},
this.$emit('create', { props: {
name: `${(this.path ? `${this.path}/` : '')}${name}`, path: {
branchId: this.branchId, type: String,
type: 'blob', required: false,
content: result, default: '',
base64: !isText,
});
},
readFile(file) {
const reader = new FileReader();
const isText = file.type.match(/text.*/) !== null;
reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true });
if (isText) {
reader.readAsText(file);
} else {
reader.readAsDataURL(file);
}
},
openFile() {
Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file));
},
startFileUpload() {
this.$refs.fileUpload.click();
},
}, },
}; showLabel: {
type: Boolean,
required: false,
default: true,
},
buttonCssClasses: {
type: String,
required: false,
default: null,
},
},
mounted() {
this.$refs.fileUpload.addEventListener('change', this.openFile);
},
beforeDestroy() {
this.$refs.fileUpload.removeEventListener('change', this.openFile);
},
methods: {
createFile(target, file, isText) {
const { name } = file;
let { result } = target;
if (!isText) {
// eslint-disable-next-line prefer-destructuring
result = result.split('base64,')[1];
}
this.$emit('create', {
name: `${this.path ? `${this.path}/` : ''}${name}`,
type: 'blob',
content: result,
base64: !isText,
});
},
readFile(file) {
const reader = new FileReader();
const isText = file.type.match(/text.*/) !== null;
reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true });
if (isText) {
reader.readAsText(file);
} else {
reader.readAsDataURL(file);
}
},
openFile() {
Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file));
},
startFileUpload() {
this.$refs.fileUpload.click();
},
},
};
</script> </script>
<template> <template>
<div> <div>
<a <item-button
href="#" :class="buttonCssClasses"
role="button" :show-label="showLabel"
@click.stop.prevent="startFileUpload" :icon-classes="showLabel ? 'mr-2' : ''"
> :label="__('Upload file')"
{{ __('Upload file') }} class="d-flex"
</a> icon="upload"
@click="startFileUpload"
/>
<input <input
id="file-upload" id="file-upload"
ref="fileUpload" ref="fileUpload"

View file

@ -40,6 +40,11 @@ export default {
default: false, default: false,
}, },
}, },
data() {
return {
mouseOver: false,
};
},
computed: { computed: {
...mapGetters([ ...mapGetters([
'getChangesInFolder', 'getChangesInFolder',
@ -142,6 +147,9 @@ export default {
hasUrlAtCurrentRoute() { hasUrlAtCurrentRoute() {
return this.$router.currentRoute.path === `/project${this.file.url}`; return this.$router.currentRoute.path === `/project${this.file.url}`;
}, },
toggleHover(over) {
this.mouseOver = over;
},
}, },
}; };
</script> </script>
@ -153,6 +161,8 @@ export default {
class="file" class="file"
role="button" role="button"
@click="clickFile" @click="clickFile"
@mouseover="toggleHover(true)"
@mouseout="toggleHover(false)"
> >
<div <div
class="file-name" class="file-name"
@ -206,6 +216,7 @@ export default {
:project-id="file.projectId" :project-id="file.projectId"
:branch="file.branchId" :branch="file.branchId"
:path="file.path" :path="file.path"
:mouse-over="mouseOver"
class="float-right prepend-left-8" class="float-right prepend-left-8"
/> />
</div> </div>

View file

@ -52,7 +52,7 @@ export const setResizingStatus = ({ commit }, resizing) => {
export const createTempEntry = ( export const createTempEntry = (
{ state, commit, dispatch }, { state, commit, dispatch },
{ branchId, name, type, content = '', base64 = false }, { name, type, content = '', base64 = false },
) => ) =>
new Promise(resolve => { new Promise(resolve => {
const worker = new FilesDecoratorWorker(); const worker = new FilesDecoratorWorker();
@ -81,7 +81,7 @@ export const createTempEntry = (
commit(types.CREATE_TMP_ENTRY, { commit(types.CREATE_TMP_ENTRY, {
data, data,
projectId: state.currentProjectId, projectId: state.currentProjectId,
branchId, branchId: state.currentBranchId,
}); });
if (type === 'blob') { if (type === 'blob') {
@ -100,7 +100,7 @@ export const createTempEntry = (
worker.postMessage({ worker.postMessage({
data: [fullName], data: [fullName],
projectId: state.currentProjectId, projectId: state.currentProjectId,
branchId, branchId: state.currentBranchId,
type, type,
tempFile: true, tempFile: true,
base64, base64,
@ -178,6 +178,13 @@ export const setLinks = ({ commit }, links) => commit(types.SET_LINKS, links);
export const setErrorMessage = ({ commit }, errorMessage) => export const setErrorMessage = ({ commit }, errorMessage) =>
commit(types.SET_ERROR_MESSAGE, errorMessage); commit(types.SET_ERROR_MESSAGE, errorMessage);
export const openNewEntryModal = ({ commit }, { type, path = '' }) => {
commit(types.OPEN_NEW_ENTRY_MODAL, { type, path });
// open the modal manually so we don't mess around with dropdown/rows
$('#ide-new-entry').modal('show');
};
export * from './actions/tree'; export * from './actions/tree';
export * from './actions/file'; export * from './actions/file';
export * from './actions/project'; export * from './actions/project';

View file

@ -74,3 +74,5 @@ export const CLEAR_PROJECTS = 'CLEAR_PROJECTS';
export const RESET_OPEN_FILES = 'RESET_OPEN_FILES'; export const RESET_OPEN_FILES = 'RESET_OPEN_FILES';
export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE'; export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export const OPEN_NEW_ENTRY_MODAL = 'OPEN_NEW_ENTRY_MODAL';

View file

@ -166,6 +166,11 @@ export default {
[types.SET_ERROR_MESSAGE](state, errorMessage) { [types.SET_ERROR_MESSAGE](state, errorMessage) {
Object.assign(state, { errorMessage }); Object.assign(state, { errorMessage });
}, },
[types.OPEN_NEW_ENTRY_MODAL](state, { type, path }) {
Object.assign(state, {
newEntryModal: { type, path },
});
},
...projectMutations, ...projectMutations,
...mergeRequestMutation, ...mergeRequestMutation,
...fileMutations, ...fileMutations,

View file

@ -26,4 +26,8 @@ export default () => ({
rightPane: null, rightPane: null,
links: {}, links: {},
errorMessage: null, errorMessage: null,
newEntryModal: {
type: '',
path: '',
},
}); });

View file

@ -45,6 +45,11 @@ export default {
emitSubmit(event) { emitSubmit(event) {
this.$emit('submit', event); this.$emit('submit', event);
}, },
opened({ propertyName }) {
if (propertyName === 'opacity') {
this.$emit('open');
}
},
}, },
}; };
</script> </script>
@ -55,6 +60,7 @@ export default {
class="modal fade" class="modal fade"
tabindex="-1" tabindex="-1"
role="dialog" role="dialog"
@transitionend="opened"
> >
<div <div
:class="modalSizeClass" :class="modalSizeClass"

View file

@ -44,6 +44,7 @@
padding-bottom: $grid-size; padding-bottom: $grid-size;
.file { .file {
height: 32px;
cursor: pointer; cursor: pointer;
&.file-active { &.file-active {
@ -716,32 +717,6 @@
justify-content: center; justify-content: center;
} }
.ide-new-btn {
.btn {
padding-top: 3px;
padding-bottom: 3px;
}
.dropdown {
display: flex;
}
.dropdown-toggle svg {
top: 0;
}
.dropdown-menu {
left: auto;
right: 0;
label {
font-weight: $gl-font-weight-normal;
padding: 5px 8px;
margin-bottom: 0;
}
}
}
.ide { .ide {
overflow: hidden; overflow: hidden;
@ -1340,3 +1315,24 @@
overflow: auto; overflow: auto;
} }
} }
.ide-entry-dropdown-toggle {
padding: $gl-padding-4;
background-color: $theme-gray-100;
&:hover {
background-color: $theme-gray-200;
}
&:active,
&:focus {
color: $white-normal;
background-color: $blue-500;
outline: 0;
}
}
.ide-new-btn .dropdown.show .ide-entry-dropdown-toggle {
color: $white-normal;
background-color: $blue-500;
}

View file

@ -0,0 +1,5 @@
---
title: Updated design of new entry dropdown in Web IDE
merge_request: 20526
author:
type: changed

View file

@ -1720,6 +1720,9 @@ msgstr ""
msgid "Create new file" msgid "Create new file"
msgstr "" msgstr ""
msgid "Create new file or directory"
msgstr ""
msgid "Create new label" msgid "Create new label"
msgstr "" msgstr ""

View file

@ -22,9 +22,7 @@ describe 'Multi-file editor new directory', :js do
end end
it 'creates directory in current directory' do it 'creates directory in current directory' do
find('.add-to-tree').click all('.ide-tree-header button').last.click
click_link('New directory')
page.within('.modal') do page.within('.modal') do
find('.form-control').set('folder name') find('.form-control').set('folder name')
@ -32,9 +30,7 @@ describe 'Multi-file editor new directory', :js do
click_button('Create directory') click_button('Create directory')
end end
find('.add-to-tree').click first('.ide-tree-header button').click
click_link('New file')
page.within('.modal-dialog') do page.within('.modal-dialog') do
find('.form-control').set('file name') find('.form-control').set('file name')

View file

@ -22,9 +22,7 @@ describe 'Multi-file editor new file', :js do
end end
it 'creates file in current directory' do it 'creates file in current directory' do
find('.add-to-tree').click first('.ide-tree-header button').click
click_link('New file')
page.within('.modal') do page.within('.modal') do
find('.form-control').set('file name') find('.form-control').set('file name')

View file

@ -24,14 +24,10 @@ describe 'Multi-file editor upload file', :js do
end end
it 'uploads text file' do it 'uploads text file' do
find('.add-to-tree').click
# make the field visible so capybara can use it # make the field visible so capybara can use it
execute_script('document.querySelector("#file-upload").classList.remove("hidden")') execute_script('document.querySelector("#file-upload").classList.remove("hidden")')
attach_file('file-upload', txt_file) attach_file('file-upload', txt_file)
find('.add-to-tree').click
expect(page).to have_selector('.multi-file-tab', text: 'doc_sample.txt') expect(page).to have_selector('.multi-file-tab', text: 'doc_sample.txt')
expect(find('.blob-editor-container .lines-content')['innerText']).to have_content(File.open(txt_file, &:readline)) expect(find('.blob-editor-container .lines-content')['innerText']).to have_content(File.open(txt_file, &:readline))
end end

View file

@ -0,0 +1,49 @@
import Vue from 'vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import Button from '~/ide/components/new_dropdown/button.vue';
describe('IDE new entry dropdown button component', () => {
let Component;
let vm;
beforeAll(() => {
Component = Vue.extend(Button);
});
beforeEach(() => {
vm = mountComponent(Component, {
label: 'Testing',
icon: 'doc-new',
});
spyOn(vm, '$emit');
});
afterEach(() => {
vm.$destroy();
});
it('renders button with label', () => {
expect(vm.$el.textContent).toContain('Testing');
});
it('renders icon', () => {
expect(vm.$el.querySelector('.ic-doc-new')).not.toBe(null);
});
it('emits click event', () => {
vm.$el.click();
expect(vm.$emit).toHaveBeenCalledWith('click');
});
it('hides label if showLabel is false', done => {
vm.showLabel = false;
vm.$nextTick(() => {
expect(vm.$el.textContent).not.toContain('Testing');
done();
});
});
});

View file

@ -13,6 +13,7 @@ describe('new dropdown component', () => {
vm = createComponentWithStore(component, store, { vm = createComponentWithStore(component, store, {
branch: 'master', branch: 'master',
path: '', path: '',
mouseOver: false,
}); });
vm.$store.state.currentProjectId = 'abcproject'; vm.$store.state.currentProjectId = 'abcproject';
@ -21,6 +22,8 @@ describe('new dropdown component', () => {
tree: [], tree: [],
}; };
spyOn(vm, 'openNewEntryModal');
vm.$mount(); vm.$mount();
}); });
@ -31,50 +34,23 @@ describe('new dropdown component', () => {
}); });
it('renders new file, upload and new directory links', () => { it('renders new file, upload and new directory links', () => {
expect(vm.$el.querySelectorAll('a')[0].textContent.trim()).toBe('New file'); const buttons = vm.$el.querySelectorAll('.dropdown-menu button');
expect(vm.$el.querySelectorAll('a')[1].textContent.trim()).toBe('Upload file'); expect(buttons[0].textContent.trim()).toBe('New file');
expect(vm.$el.querySelectorAll('a')[2].textContent.trim()).toBe('New directory'); expect(buttons[1].textContent.trim()).toBe('Upload file');
expect(buttons[2].textContent.trim()).toBe('New directory');
}); });
describe('createNewItem', () => { describe('createNewItem', () => {
it('sets modalType to blob when new file is clicked', () => { it('sets modalType to blob when new file is clicked', () => {
vm.$el.querySelectorAll('a')[0].click(); vm.$el.querySelectorAll('.dropdown-menu button')[0].click();
expect(vm.modalType).toBe('blob'); expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'blob', path: '' });
}); });
it('sets modalType to tree when new directory is clicked', () => { it('sets modalType to tree when new directory is clicked', () => {
vm.$el.querySelectorAll('a')[2].click(); vm.$el.querySelectorAll('.dropdown-menu button')[2].click();
expect(vm.modalType).toBe('tree'); expect(vm.openNewEntryModal).toHaveBeenCalledWith({ type: 'tree', path: '' });
});
it('opens modal when link is clicked', done => {
vm.$el.querySelectorAll('a')[0].click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.modal')).not.toBeNull();
done();
});
});
});
describe('hideModal', () => {
beforeAll(done => {
vm.openModal = true;
Vue.nextTick(done);
});
it('closes modal after toggling', done => {
vm.hideModal();
Vue.nextTick()
.then(() => {
expect(vm.$el.querySelector('.modal')).toBeNull();
})
.then(done)
.catch(done.fail);
}); });
}); });

View file

@ -1,6 +1,7 @@
import Vue from 'vue'; import Vue from 'vue';
import { createStore } from '~/ide/stores';
import modal from '~/ide/components/new_dropdown/modal.vue'; import modal from '~/ide/components/new_dropdown/modal.vue';
import createComponent from 'spec/helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
describe('new file modal component', () => { describe('new file modal component', () => {
const Component = Vue.extend(modal); const Component = Vue.extend(modal);
@ -13,13 +14,15 @@ describe('new file modal component', () => {
['tree', 'blob'].forEach(type => { ['tree', 'blob'].forEach(type => {
describe(type, () => { describe(type, () => {
beforeEach(() => { beforeEach(() => {
vm = createComponent(Component, { const store = createStore();
store.state.newEntryModal = {
type, type,
branchId: 'master',
path: '', path: '',
}); };
vm.entryName = 'testing'; vm = createComponentWithStore(Component, store).$mount();
vm.name = 'testing';
}); });
it(`sets modal title as ${type}`, () => { it(`sets modal title as ${type}`, () => {
@ -40,12 +43,11 @@ describe('new file modal component', () => {
describe('createEntryInStore', () => { describe('createEntryInStore', () => {
it('$emits create', () => { it('$emits create', () => {
spyOn(vm, '$emit'); spyOn(vm, 'createTempEntry');
vm.createEntryInStore(); vm.createEntryInStore();
expect(vm.$emit).toHaveBeenCalledWith('create', { expect(vm.createTempEntry).toHaveBeenCalledWith({
branchId: 'master',
name: 'testing', name: 'testing',
type, type,
}); });
@ -53,22 +55,4 @@ describe('new file modal component', () => {
}); });
}); });
}); });
it('focuses field on mount', () => {
document.body.innerHTML += '<div class="js-test"></div>';
vm = createComponent(
Component,
{
type: 'tree',
branchId: 'master',
path: '',
},
'.js-test',
);
expect(document.activeElement).toBe(vm.$refs.fieldName);
vm.$el.remove();
});
}); });

View file

@ -9,7 +9,6 @@ describe('new dropdown upload', () => {
const Component = Vue.extend(upload); const Component = Vue.extend(upload);
vm = createComponent(Component, { vm = createComponent(Component, {
branchId: 'master',
path: '', path: '',
}); });
@ -65,7 +64,6 @@ describe('new dropdown upload', () => {
expect(vm.$emit).toHaveBeenCalledWith('create', { expect(vm.$emit).toHaveBeenCalledWith('create', {
name: file.name, name: file.name,
branchId: 'master',
type: 'blob', type: 'blob',
content: target.result, content: target.result,
base64: false, base64: false,
@ -77,7 +75,6 @@ describe('new dropdown upload', () => {
expect(vm.$emit).toHaveBeenCalledWith('create', { expect(vm.$emit).toHaveBeenCalledWith('create', {
name: file.name, name: file.name,
branchId: 'master',
type: 'blob', type: 'blob',
content: binaryTarget.result.split('base64,')[1], content: binaryTarget.result.split('base64,')[1],
base64: true, base64: true,