Commit 355d8ef7 authored by Filipa Lacerda's avatar Filipa Lacerda

Adds create option in filtered dropdown

In the filtered search dropdopwn adds a button
to enable creation of missing element.
parent 8ae38ca2
<script> <script>
import $ from 'jquery'; import $ from 'jquery';
import { GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
/** /**
* Renders a split dropdown with * Renders a split dropdown with
* an input that allows to search through the given * an input that allows to search through the given
* array of options. * array of options.
*
* When there are no results and `showCreateMode` is true
* it renders a create button with the value typed.
*/ */
export default { export default {
name: 'FilteredSearchDropdown', name: 'FilteredSearchDropdown',
components: { components: {
Icon, Icon,
GlButton,
}, },
props: { props: {
title: { title: {
...@@ -43,6 +49,16 @@ export default { ...@@ -43,6 +49,16 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
showCreateMode: {
type: Boolean,
required: false,
default: false,
},
createButtonText: {
type: String,
required: false,
default: __('Create'),
},
}, },
data() { data() {
return { return {
...@@ -64,6 +80,12 @@ export default { ...@@ -64,6 +80,12 @@ export default {
return this.items.slice(0, this.visibleItems); return this.items.slice(0, this.visibleItems);
}, },
computedCreateButtonText() {
return `${this.createButtonText} ${this.filter}`;
},
shouldRenderCreateButton() {
return this.showCreateMode && this.filteredResults.length === 0 && this.filter !== '';
},
}, },
mounted() { mounted() {
/** /**
...@@ -112,10 +134,20 @@ export default { ...@@ -112,10 +134,20 @@ export default {
<div class="dropdown-content"> <div class="dropdown-content">
<ul> <ul>
<li v-for="(result, i) in filteredResults" :key="i" class="js-filtered-dropdown-result"> <li v-for="(result, i) in filteredResults" :key="i" class="js-filtered-dropdown-result">
<slot name="result" :result="result"> {{ result[filterKey] }} </slot> <slot name="result" :result="result">{{ result[filterKey] }}</slot>
</li> </li>
</ul> </ul>
</div> </div>
<div v-if="shouldRenderCreateButton" class="dropdown-footer">
<slot name="footer" :filter="filter">
<gl-button
class="js-dropdown-create-button btn-transparent"
@click="$emit('createItem', filter)"
>{{ computedCreateButtonText }}</gl-button
>
</slot>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -88,4 +88,103 @@ describe('Filtered search dropdown', () => { ...@@ -88,4 +88,103 @@ describe('Filtered search dropdown', () => {
}); });
}); });
}); });
describe('with create mode enabled', () => {
describe('when there are no matches', () => {
beforeEach(() => {
vm = mountComponent(Component, {
items: [
{ title: 'One' },
{ title: 'Two/three' },
{ title: 'Three four' },
{ title: 'Five' },
],
filterKey: 'title',
showCreateMode: true,
});
vm.$el.querySelector('.js-filtered-dropdown-input').value = 'eleven';
vm.$el.querySelector('.js-filtered-dropdown-input').dispatchEvent(new Event('input'));
});
it('renders a create button', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.js-dropdown-create-button')).not.toBeNull();
done();
});
});
it('renders computed button text', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.js-dropdown-create-button').textContent.trim()).toEqual(
'Create eleven',
);
done();
});
});
describe('on click create button', () => {
it('emits createItem event with the filter', done => {
spyOn(vm, '$emit');
vm.$nextTick(() => {
vm.$el.querySelector('.js-dropdown-create-button').click();
expect(vm.$emit).toHaveBeenCalledWith('createItem', 'eleven');
done();
});
});
});
});
describe('when there are matches', () => {
beforeEach(() => {
vm = mountComponent(Component, {
items: [
{ title: 'One' },
{ title: 'Two/three' },
{ title: 'Three four' },
{ title: 'Five' },
],
filterKey: 'title',
showCreateMode: true,
});
vm.$el.querySelector('.js-filtered-dropdown-input').value = 'one';
vm.$el.querySelector('.js-filtered-dropdown-input').dispatchEvent(new Event('input'));
});
it('does not render a create button', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.js-dropdown-create-button')).toBeNull();
done();
});
});
});
});
describe('with create mode disabled', () => {
describe('when there are no matches', () => {
beforeEach(() => {
vm = mountComponent(Component, {
items: [
{ title: 'One' },
{ title: 'Two/three' },
{ title: 'Three four' },
{ title: 'Five' },
],
filterKey: 'title',
});
vm.$el.querySelector('.js-filtered-dropdown-input').value = 'eleven';
vm.$el.querySelector('.js-filtered-dropdown-input').dispatchEvent(new Event('input'));
});
it('does not render a create button', done => {
vm.$nextTick(() => {
expect(vm.$el.querySelector('.js-dropdown-create-button')).toBeNull();
done();
});
});
});
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment