Commit 2a55c81c authored by Daniel Tian's avatar Daniel Tian Committed by Kushal Pandya

Improve search box for filter dropdowns on vulnerability page

1. Auto focus search box when dropdown is opened
2. Change placeholder text from "Filter..." to "Search"
3. Emit dropdown-show and dropdown-hide events when dropdown is toggled
4. Hide the browser's autocomplete
5. Always show search box at top instead of scrolling with list
parent df5fcb4e
......@@ -44,6 +44,12 @@ export default {
emitInput(value) {
this.$emit('input', value);
},
async emitDropdownShow() {
this.$emit('dropdown-show');
// Focus on the search box when the dropdown is opened.
await this.$nextTick();
this.$refs.searchBox?.focusInput();
},
},
};
</script>
......@@ -56,6 +62,8 @@ export default {
menu-class="dropdown-extended-height"
:header-text="name"
toggle-class="gl-w-full"
@show="emitDropdownShow"
@hide="$emit('dropdown-hide')"
>
<template #button-content>
<gl-truncate
......@@ -69,11 +77,14 @@ export default {
<gl-icon name="chevron-down" class="gl-flex-shrink-0 gl-ml-auto" />
</template>
<gl-search-box-by-type
v-if="showSearchBox"
:placeholder="__('Filter...')"
@input="emitInput"
/>
<template v-if="showSearchBox" #header>
<gl-search-box-by-type
ref="searchBox"
:placeholder="__('Search')"
autocomplete="off"
@input="emitInput"
/>
</template>
<slot>
<gl-dropdown-text>
......
......@@ -10,15 +10,16 @@ describe('Filter Body component', () => {
selectedOptions: [],
};
const createComponent = (props, slotContent = '') => {
const createComponent = (props, options) => {
wrapper = mount(FilterBody, {
propsData: { ...defaultProps, ...props },
slots: { default: slotContent },
...options,
});
};
const dropdown = () => wrapper.findComponent(GlDropdown);
const dropdownButton = () => wrapper.find('.dropdown-toggle');
const searchBox = () => wrapper.find(GlSearchBoxByType);
const searchBox = () => wrapper.findComponent(GlSearchBoxByType);
afterEach(() => {
wrapper.destroy();
......@@ -28,7 +29,21 @@ describe('Filter Body component', () => {
createComponent();
expect(wrapper.find('[data-testid="name"]').text()).toBe(defaultProps.name);
expect(wrapper.find(GlDropdown).props('headerText')).toBe(defaultProps.name);
expect(dropdown().props('headerText')).toBe(defaultProps.name);
});
it('emits dropdown-show event when dropdown is shown', () => {
createComponent();
dropdown().vm.$emit('show');
expect(wrapper.emitted('dropdown-show')).toHaveLength(1);
});
it('emits dropdown-hide event when dropdown is hidden', () => {
createComponent();
dropdown().vm.$emit('hide');
expect(wrapper.emitted('dropdown-hide')).toHaveLength(1);
});
describe('dropdown button', () => {
......@@ -56,6 +71,15 @@ describe('Filter Body component', () => {
expect(searchBox().exists()).toBe(show);
});
it('is focused when the dropdown is opened', async () => {
createComponent({ showSearchBox: true }, { attachTo: document.body });
const spy = jest.spyOn(searchBox().vm, 'focusInput');
dropdown().vm.$emit('show');
await wrapper.vm.$nextTick();
expect(spy).toHaveBeenCalledTimes(1);
});
it('emits input event on component when search box input is changed', () => {
const text = 'abc';
createComponent({ showSearchBox: true });
......@@ -68,7 +92,7 @@ describe('Filter Body component', () => {
describe('dropdown body', () => {
it('shows slot content', () => {
const slotContent = 'some slot content';
createComponent({}, slotContent);
createComponent({}, { slots: { default: slotContent } });
expect(wrapper.text()).toContain(slotContent);
});
......
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