Commit 670254b6 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska Committed by David O'Regan

Replace GlDeprecatedDropdown in related_items_tree

parent 3ae06d3d
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import { mapState, mapActions } from 'vuex'; import { mapState, mapActions } from 'vuex';
import { import {
GlButton, GlButton,
GlDeprecatedDropdown, GlDropdown,
GlDeprecatedDropdownItem, GlDropdownItem,
GlFormInput, GlFormInput,
GlSearchBoxByType, GlSearchBoxByType,
GlLoadingIcon, GlLoadingIcon,
...@@ -17,8 +17,8 @@ import { SEARCH_DEBOUNCE } from '../constants'; ...@@ -17,8 +17,8 @@ import { SEARCH_DEBOUNCE } from '../constants';
export default { export default {
components: { components: {
GlButton, GlButton,
GlDeprecatedDropdown, GlDropdown,
GlDeprecatedDropdownItem, GlDropdownItem,
GlFormInput, GlFormInput,
GlSearchBoxByType, GlSearchBoxByType,
GlLoadingIcon, GlLoadingIcon,
...@@ -29,7 +29,6 @@ export default { ...@@ -29,7 +29,6 @@ export default {
selectedProject: null, selectedProject: null,
searchKey: '', searchKey: '',
title: '', title: '',
preventDropdownClose: false,
}; };
}, },
computed: { computed: {
...@@ -83,32 +82,6 @@ export default { ...@@ -83,32 +82,6 @@ export default {
this.searchKey = ''; this.searchKey = '';
this.fetchProjects(); this.fetchProjects();
}, },
handleDropdownHide(e) {
// Check if dropdown closure is to be prevented.
if (this.preventDropdownClose) {
e.preventDefault();
this.preventDropdownClose = false;
}
},
/**
* As GlDropdown can get closed if any item within
* it is clicked, we have to work around that behaviour
* by preventing dropdown close if user has clicked
* clear button on search input field. This hack
* won't be required once we add support for
* `BDropdownForm` https://bootstrap-vue.js.org/docs/components/dropdown#b-dropdown-form
* within GitLab UI.
*/
handleSearchInputContainerClick({ target }) {
// Check if clicked target was an icon.
if (
target?.classList.contains('gl-icon') ||
target?.getAttribute('href')?.includes('clear')
) {
// Enable flag to prevent dropdown close.
this.preventDropdownClose = true;
}
},
}, },
}; };
</script> </script>
...@@ -129,43 +102,41 @@ export default { ...@@ -129,43 +102,41 @@ export default {
</div> </div>
<div class="col-sm"> <div class="col-sm">
<label class="label-bold">{{ __('Project') }}</label> <label class="label-bold">{{ __('Project') }}</label>
<gl-deprecated-dropdown <gl-dropdown
ref="dropdownButton" ref="dropdownButton"
:text="dropdownToggleText" :text="dropdownToggleText"
class="w-100 projects-dropdown" class="gl-w-full projects-dropdown"
menu-class="w-100 overflow-hidden" menu-class="gl-w-full! gl-overflow-hidden!"
toggle-class="d-flex align-items-center justify-content-between text-truncate" toggle-class="gl-display-flex gl-align-items-center gl-justify-content-between gl-text-truncate"
@show="handleDropdownShow" @show="handleDropdownShow"
@hide="handleDropdownHide"
> >
<div class="mx-2 mb-1" @click="handleSearchInputContainerClick"> <gl-search-box-by-type
<gl-search-box-by-type ref="searchInputField"
ref="searchInputField" v-model="searchKey"
v-model="searchKey" class="gl-mx-3 gl-mb-2"
:disabled="projectsFetchInProgress" :disabled="projectsFetchInProgress"
/> />
</div>
<gl-loading-icon <gl-loading-icon
v-show="projectsFetchInProgress" v-show="projectsFetchInProgress"
class="projects-fetch-loading align-items-center p-2" class="projects-fetch-loading gl-align-items-center gl-p-3"
size="md" size="md"
/> />
<div v-if="!projectsFetchInProgress" class="dropdown-contents overflow-auto p-1"> <div v-if="!projectsFetchInProgress" class="dropdown-contents gl-overflow-auto gl-p-2">
<span v-if="!projects.length" class="d-block text-center p-2">{{ <span v-if="!projects.length" class="gl-display-block text-center gl-p-3">{{
__('No matches found') __('No matches found')
}}</span> }}</span>
<gl-deprecated-dropdown-item <gl-dropdown-item
v-for="project in projects" v-for="project in projects"
:key="project.id" :key="project.id"
class="w-100" class="gl-w-full"
:secondary-text="project.namespace.name"
@click="selectedProject = project" @click="selectedProject = project"
> >
<project-avatar :project="project" :size="32" /> <project-avatar :project="project" :size="32" />
{{ project.name }} {{ project.name }}
<div class="text-secondary">{{ project.namespace.name }}</div> </gl-dropdown-item>
</gl-deprecated-dropdown-item>
</div> </div>
</gl-deprecated-dropdown> </gl-dropdown>
</div> </div>
</div> </div>
......
<script> <script>
import { import { GlDropdown, GlDropdownDivider, GlDropdownSectionHeader, GlDropdownItem } from '@gitlab/ui';
GlDeprecatedDropdown,
GlDeprecatedDropdownDivider,
GlDeprecatedDropdownHeader,
GlDeprecatedDropdownItem,
} from '@gitlab/ui';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
...@@ -34,10 +29,10 @@ export default { ...@@ -34,10 +29,10 @@ export default {
epicActionItems, epicActionItems,
issueActionItems, issueActionItems,
components: { components: {
GlDeprecatedDropdown, GlDropdown,
GlDeprecatedDropdownDivider, GlDropdownDivider,
GlDeprecatedDropdownHeader, GlDropdownSectionHeader,
GlDeprecatedDropdownItem, GlDropdownItem,
}, },
props: { props: {
allowSubEpics: { allowSubEpics: {
...@@ -55,32 +50,25 @@ export default { ...@@ -55,32 +50,25 @@ export default {
</script> </script>
<template> <template>
<gl-deprecated-dropdown <gl-dropdown :text="__('Add')" data-qa-selector="epic_issue_actions_split_button" right>
:text="__('Add')" <gl-dropdown-section-header>{{ __('Issue') }}</gl-dropdown-section-header>
variant="secondary" <gl-dropdown-item
data-qa-selector="epic_issue_actions_split_button"
right
>
<gl-deprecated-dropdown-header>{{ __('Issue') }}</gl-deprecated-dropdown-header>
<gl-deprecated-dropdown-item
v-for="item in $options.issueActionItems" v-for="item in $options.issueActionItems"
:key="item.eventName" :key="item.eventName"
active-class="is-active"
@click="change(item)" @click="change(item)"
> >
{{ item.title }} {{ item.title }}
</gl-deprecated-dropdown-item> </gl-dropdown-item>
<template v-if="allowSubEpics"> <template v-if="allowSubEpics">
<gl-deprecated-dropdown-divider /> <gl-dropdown-divider />
<gl-deprecated-dropdown-header>{{ __('Epic') }}</gl-deprecated-dropdown-header> <gl-dropdown-section-header>{{ __('Epic') }}</gl-dropdown-section-header>
<gl-deprecated-dropdown-item <gl-dropdown-item
v-for="item in $options.epicActionItems" v-for="item in $options.epicActionItems"
:key="item.eventName" :key="item.eventName"
active-class="is-active"
@click="change(item)" @click="change(item)"
> >
{{ item.title }} {{ item.title }}
</gl-deprecated-dropdown-item> </gl-dropdown-item>
</template> </template>
</gl-deprecated-dropdown> </gl-dropdown>
</template> </template>
---
title: Update the create issue form and epic issue actions dropdowns to use our Pajamas compliant components
merge_request: 50633
author:
type: other
import { import {
GlButton, GlButton,
GlDeprecatedDropdown, GlDropdown,
GlDeprecatedDropdownItem, GlDropdownItem,
GlFormInput, GlFormInput,
GlSearchBoxByType, GlSearchBoxByType,
GlLoadingIcon, GlLoadingIcon,
...@@ -48,7 +48,6 @@ describe('CreateIssueForm', () => { ...@@ -48,7 +48,6 @@ describe('CreateIssueForm', () => {
expect(wrapper.vm.selectedProject).toBeNull(); expect(wrapper.vm.selectedProject).toBeNull();
expect(wrapper.vm.searchKey).toBe(''); expect(wrapper.vm.searchKey).toBe('');
expect(wrapper.vm.title).toBe(''); expect(wrapper.vm.title).toBe('');
expect(wrapper.vm.preventDropdownClose).toBe(false);
}); });
}); });
...@@ -111,51 +110,12 @@ describe('CreateIssueForm', () => { ...@@ -111,51 +110,12 @@ describe('CreateIssueForm', () => {
expect(handleDropdownShow).toHaveBeenCalled(); expect(handleDropdownShow).toHaveBeenCalled();
}); });
}); });
describe('handleDropdownHide', () => {
it('sets `searchKey` prop to empty string and calls action `fetchProjects`', () => {
const event = {
preventDefault: jest.fn(),
};
const preventDefault = jest.spyOn(event, 'preventDefault');
wrapper.setData({
preventDropdownClose: true,
});
wrapper.vm.handleDropdownHide(event);
return wrapper.vm.$nextTick(() => {
expect(preventDefault).toHaveBeenCalled();
expect(wrapper.vm.preventDropdownClose).toBe(false);
});
});
});
describe('handleSearchInputContainerClick', () => {
it('sets `preventDropdownClose` to `true` when target element contains class `gl-icon`', () => {
const target = document.createElement('span');
target.setAttribute('class', 'gl-icon');
wrapper.vm.handleSearchInputContainerClick({ target });
expect(wrapper.vm.preventDropdownClose).toBe(true);
});
it('sets `preventDropdownClose` to `true` when target element href contains text `clear`', () => {
const target = document.createElement('user');
target.setAttribute('href', 'foo.svg#clear');
wrapper.vm.handleSearchInputContainerClick({ target });
expect(wrapper.vm.preventDropdownClose).toBe(true);
});
});
}); });
describe('templates', () => { describe('templates', () => {
it('renders Issue title input field', () => { it('renders Issue title input field', () => {
const issueTitleFieldLabel = wrapper.findAll('label').at(0); const issueTitleFieldLabel = wrapper.findAll('label').at(0);
const issueTitleFieldInput = wrapper.find(GlFormInput); const issueTitleFieldInput = wrapper.findComponent(GlFormInput);
expect(issueTitleFieldLabel.text()).toBe('Title'); expect(issueTitleFieldLabel.text()).toBe('Title');
expect(issueTitleFieldInput.attributes('placeholder')).toBe('New issue title'); expect(issueTitleFieldInput.attributes('placeholder')).toBe('New issue title');
...@@ -163,7 +123,7 @@ describe('CreateIssueForm', () => { ...@@ -163,7 +123,7 @@ describe('CreateIssueForm', () => {
it('renders Projects dropdown field', () => { it('renders Projects dropdown field', () => {
const projectsDropdownLabel = wrapper.findAll('label').at(1); const projectsDropdownLabel = wrapper.findAll('label').at(1);
const projectsDropdownButton = wrapper.find(GlDeprecatedDropdown); const projectsDropdownButton = wrapper.findComponent(GlDropdown);
expect(projectsDropdownLabel.text()).toBe('Project'); expect(projectsDropdownLabel.text()).toBe('Project');
expect(projectsDropdownButton.props('text')).toBe('Select a project'); expect(projectsDropdownButton.props('text')).toBe('Select a project');
...@@ -173,15 +133,16 @@ describe('CreateIssueForm', () => { ...@@ -173,15 +133,16 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('receiveProjectsSuccess', mockProjects); wrapper.vm.$store.dispatch('receiveProjectsSuccess', mockProjects);
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
const projectsDropdownButton = wrapper.find(GlDeprecatedDropdown); const projectsDropdownButton = wrapper.findComponent(GlDropdown);
const dropdownItems = projectsDropdownButton.findAll(GlDeprecatedDropdownItem); const dropdownItems = projectsDropdownButton.findAllComponents(GlDropdownItem);
const dropdownItem = dropdownItems.at(0);
expect(projectsDropdownButton.find(GlSearchBoxByType).exists()).toBe(true); expect(projectsDropdownButton.findComponent(GlSearchBoxByType).exists()).toBe(true);
expect(projectsDropdownButton.find(GlLoadingIcon).exists()).toBe(true); expect(projectsDropdownButton.findComponent(GlLoadingIcon).exists()).toBe(true);
expect(dropdownItems).toHaveLength(mockProjects.length); expect(dropdownItems).toHaveLength(mockProjects.length);
expect(dropdownItems.at(0).text()).toContain(mockProjects[0].name); expect(dropdownItem.text()).toBe(mockProjects[0].name);
expect(dropdownItems.at(0).text()).toContain(mockProjects[0].namespace.name); expect(dropdownItem.attributes('secondarytext')).toBe(mockProjects[0].namespace.name);
expect(dropdownItems.at(0).find(ProjectAvatar).exists()).toBe(true); expect(dropdownItem.findComponent(ProjectAvatar).exists()).toBe(true);
}); });
}); });
...@@ -190,7 +151,7 @@ describe('CreateIssueForm', () => { ...@@ -190,7 +151,7 @@ describe('CreateIssueForm', () => {
const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey); const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey);
jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn()); jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn());
wrapper.find(GlDeprecatedDropdown).trigger('click'); wrapper.findComponent(GlDropdown).trigger('click');
wrapper.setData({ wrapper.setData({
searchKey, searchKey,
...@@ -202,7 +163,7 @@ describe('CreateIssueForm', () => { ...@@ -202,7 +163,7 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('receiveProjectsSuccess', filteredMockProjects); wrapper.vm.$store.dispatch('receiveProjectsSuccess', filteredMockProjects);
}) })
.then(() => { .then(() => {
expect(wrapper.findAll(GlDeprecatedDropdownItem)).toHaveLength(1); expect(wrapper.findAllComponents(GlDropdownItem)).toHaveLength(1);
}); });
}); });
...@@ -211,7 +172,7 @@ describe('CreateIssueForm', () => { ...@@ -211,7 +172,7 @@ describe('CreateIssueForm', () => {
const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey); const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey);
jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn()); jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn());
wrapper.find(GlDeprecatedDropdown).trigger('click'); wrapper.findComponent(GlDropdown).trigger('click');
wrapper.setData({ wrapper.setData({
searchKey, searchKey,
...@@ -228,7 +189,7 @@ describe('CreateIssueForm', () => { ...@@ -228,7 +189,7 @@ describe('CreateIssueForm', () => {
}); });
it('renders `Create issue` button', () => { it('renders `Create issue` button', () => {
const createIssueButton = wrapper.findAll(GlButton).at(0); const createIssueButton = wrapper.findAllComponents(GlButton).at(0);
expect(createIssueButton.exists()).toBe(true); expect(createIssueButton.exists()).toBe(true);
expect(createIssueButton.text()).toBe('Create issue'); expect(createIssueButton.text()).toBe('Create issue');
...@@ -238,7 +199,7 @@ describe('CreateIssueForm', () => { ...@@ -238,7 +199,7 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('requestCreateItem'); wrapper.vm.$store.dispatch('requestCreateItem');
return wrapper.vm.$nextTick(() => { return wrapper.vm.$nextTick(() => {
const createIssueButton = wrapper.findAll(GlButton).at(0); const createIssueButton = wrapper.findAllComponents(GlButton).at(0);
expect(createIssueButton.exists()).toBe(true); expect(createIssueButton.exists()).toBe(true);
expect(createIssueButton.props('disabled')).toBe(true); expect(createIssueButton.props('disabled')).toBe(true);
...@@ -247,7 +208,7 @@ describe('CreateIssueForm', () => { ...@@ -247,7 +208,7 @@ describe('CreateIssueForm', () => {
}); });
it('renders `Cancel` button', () => { it('renders `Cancel` button', () => {
const cancelButton = wrapper.findAll(GlButton).at(1); const cancelButton = wrapper.findAllComponents(GlButton).at(1);
expect(cancelButton.exists()).toBe(true); expect(cancelButton.exists()).toBe(true);
expect(cancelButton.text()).toBe('Cancel'); expect(cancelButton.text()).toBe('Cancel');
......
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