Commit e94c009e authored by David O'Regan's avatar David O'Regan

Merge branch '233596-replace-deprecated-dropdown' into 'master'

Replace GlDeprecatedDropdown in related_items_tree

See merge request gitlab-org/gitlab!50633
parents af111c5a 670254b6
......@@ -2,8 +2,8 @@
import { mapState, mapActions } from 'vuex';
import {
GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownItem,
GlFormInput,
GlSearchBoxByType,
GlLoadingIcon,
......@@ -17,8 +17,8 @@ import { SEARCH_DEBOUNCE } from '../constants';
export default {
components: {
GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownItem,
GlFormInput,
GlSearchBoxByType,
GlLoadingIcon,
......@@ -29,7 +29,6 @@ export default {
selectedProject: null,
searchKey: '',
title: '',
preventDropdownClose: false,
};
},
computed: {
......@@ -83,32 +82,6 @@ export default {
this.searchKey = '';
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>
......@@ -129,43 +102,41 @@ export default {
</div>
<div class="col-sm">
<label class="label-bold">{{ __('Project') }}</label>
<gl-deprecated-dropdown
<gl-dropdown
ref="dropdownButton"
:text="dropdownToggleText"
class="w-100 projects-dropdown"
menu-class="w-100 overflow-hidden"
toggle-class="d-flex align-items-center justify-content-between text-truncate"
class="gl-w-full projects-dropdown"
menu-class="gl-w-full! gl-overflow-hidden!"
toggle-class="gl-display-flex gl-align-items-center gl-justify-content-between gl-text-truncate"
@show="handleDropdownShow"
@hide="handleDropdownHide"
>
<div class="mx-2 mb-1" @click="handleSearchInputContainerClick">
<gl-search-box-by-type
ref="searchInputField"
v-model="searchKey"
:disabled="projectsFetchInProgress"
/>
</div>
<gl-search-box-by-type
ref="searchInputField"
v-model="searchKey"
class="gl-mx-3 gl-mb-2"
:disabled="projectsFetchInProgress"
/>
<gl-loading-icon
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"
/>
<div v-if="!projectsFetchInProgress" class="dropdown-contents overflow-auto p-1">
<span v-if="!projects.length" class="d-block text-center p-2">{{
<div v-if="!projectsFetchInProgress" class="dropdown-contents gl-overflow-auto gl-p-2">
<span v-if="!projects.length" class="gl-display-block text-center gl-p-3">{{
__('No matches found')
}}</span>
<gl-deprecated-dropdown-item
<gl-dropdown-item
v-for="project in projects"
:key="project.id"
class="w-100"
class="gl-w-full"
:secondary-text="project.namespace.name"
@click="selectedProject = project"
>
<project-avatar :project="project" :size="32" />
{{ project.name }}
<div class="text-secondary">{{ project.namespace.name }}</div>
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
</div>
</gl-deprecated-dropdown>
</gl-dropdown>
</div>
</div>
......
<script>
import {
GlDeprecatedDropdown,
GlDeprecatedDropdownDivider,
GlDeprecatedDropdownHeader,
GlDeprecatedDropdownItem,
} from '@gitlab/ui';
import { GlDropdown, GlDropdownDivider, GlDropdownSectionHeader, GlDropdownItem } from '@gitlab/ui';
import { s__, __ } from '~/locale';
......@@ -34,10 +29,10 @@ export default {
epicActionItems,
issueActionItems,
components: {
GlDeprecatedDropdown,
GlDeprecatedDropdownDivider,
GlDeprecatedDropdownHeader,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownDivider,
GlDropdownSectionHeader,
GlDropdownItem,
},
props: {
allowSubEpics: {
......@@ -55,32 +50,25 @@ export default {
</script>
<template>
<gl-deprecated-dropdown
:text="__('Add')"
variant="secondary"
data-qa-selector="epic_issue_actions_split_button"
right
>
<gl-deprecated-dropdown-header>{{ __('Issue') }}</gl-deprecated-dropdown-header>
<gl-deprecated-dropdown-item
<gl-dropdown :text="__('Add')" data-qa-selector="epic_issue_actions_split_button" right>
<gl-dropdown-section-header>{{ __('Issue') }}</gl-dropdown-section-header>
<gl-dropdown-item
v-for="item in $options.issueActionItems"
:key="item.eventName"
active-class="is-active"
@click="change(item)"
>
{{ item.title }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
<template v-if="allowSubEpics">
<gl-deprecated-dropdown-divider />
<gl-deprecated-dropdown-header>{{ __('Epic') }}</gl-deprecated-dropdown-header>
<gl-deprecated-dropdown-item
<gl-dropdown-divider />
<gl-dropdown-section-header>{{ __('Epic') }}</gl-dropdown-section-header>
<gl-dropdown-item
v-for="item in $options.epicActionItems"
:key="item.eventName"
active-class="is-active"
@click="change(item)"
>
{{ item.title }}
</gl-deprecated-dropdown-item>
</gl-dropdown-item>
</template>
</gl-deprecated-dropdown>
</gl-dropdown>
</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 {
GlButton,
GlDeprecatedDropdown,
GlDeprecatedDropdownItem,
GlDropdown,
GlDropdownItem,
GlFormInput,
GlSearchBoxByType,
GlLoadingIcon,
......@@ -48,7 +48,6 @@ describe('CreateIssueForm', () => {
expect(wrapper.vm.selectedProject).toBeNull();
expect(wrapper.vm.searchKey).toBe('');
expect(wrapper.vm.title).toBe('');
expect(wrapper.vm.preventDropdownClose).toBe(false);
});
});
......@@ -111,51 +110,12 @@ describe('CreateIssueForm', () => {
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', () => {
it('renders Issue title input field', () => {
const issueTitleFieldLabel = wrapper.findAll('label').at(0);
const issueTitleFieldInput = wrapper.find(GlFormInput);
const issueTitleFieldInput = wrapper.findComponent(GlFormInput);
expect(issueTitleFieldLabel.text()).toBe('Title');
expect(issueTitleFieldInput.attributes('placeholder')).toBe('New issue title');
......@@ -163,7 +123,7 @@ describe('CreateIssueForm', () => {
it('renders Projects dropdown field', () => {
const projectsDropdownLabel = wrapper.findAll('label').at(1);
const projectsDropdownButton = wrapper.find(GlDeprecatedDropdown);
const projectsDropdownButton = wrapper.findComponent(GlDropdown);
expect(projectsDropdownLabel.text()).toBe('Project');
expect(projectsDropdownButton.props('text')).toBe('Select a project');
......@@ -173,15 +133,16 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('receiveProjectsSuccess', mockProjects);
return wrapper.vm.$nextTick(() => {
const projectsDropdownButton = wrapper.find(GlDeprecatedDropdown);
const dropdownItems = projectsDropdownButton.findAll(GlDeprecatedDropdownItem);
const projectsDropdownButton = wrapper.findComponent(GlDropdown);
const dropdownItems = projectsDropdownButton.findAllComponents(GlDropdownItem);
const dropdownItem = dropdownItems.at(0);
expect(projectsDropdownButton.find(GlSearchBoxByType).exists()).toBe(true);
expect(projectsDropdownButton.find(GlLoadingIcon).exists()).toBe(true);
expect(projectsDropdownButton.findComponent(GlSearchBoxByType).exists()).toBe(true);
expect(projectsDropdownButton.findComponent(GlLoadingIcon).exists()).toBe(true);
expect(dropdownItems).toHaveLength(mockProjects.length);
expect(dropdownItems.at(0).text()).toContain(mockProjects[0].name);
expect(dropdownItems.at(0).text()).toContain(mockProjects[0].namespace.name);
expect(dropdownItems.at(0).find(ProjectAvatar).exists()).toBe(true);
expect(dropdownItem.text()).toBe(mockProjects[0].name);
expect(dropdownItem.attributes('secondarytext')).toBe(mockProjects[0].namespace.name);
expect(dropdownItem.findComponent(ProjectAvatar).exists()).toBe(true);
});
});
......@@ -190,7 +151,7 @@ describe('CreateIssueForm', () => {
const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey);
jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn());
wrapper.find(GlDeprecatedDropdown).trigger('click');
wrapper.findComponent(GlDropdown).trigger('click');
wrapper.setData({
searchKey,
......@@ -202,7 +163,7 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('receiveProjectsSuccess', filteredMockProjects);
})
.then(() => {
expect(wrapper.findAll(GlDeprecatedDropdownItem)).toHaveLength(1);
expect(wrapper.findAllComponents(GlDropdownItem)).toHaveLength(1);
});
});
......@@ -211,7 +172,7 @@ describe('CreateIssueForm', () => {
const filteredMockProjects = mockProjects.filter((project) => project.name === searchKey);
jest.spyOn(wrapper.vm, 'fetchProjects').mockImplementation(jest.fn());
wrapper.find(GlDeprecatedDropdown).trigger('click');
wrapper.findComponent(GlDropdown).trigger('click');
wrapper.setData({
searchKey,
......@@ -228,7 +189,7 @@ describe('CreateIssueForm', () => {
});
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.text()).toBe('Create issue');
......@@ -238,7 +199,7 @@ describe('CreateIssueForm', () => {
wrapper.vm.$store.dispatch('requestCreateItem');
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.props('disabled')).toBe(true);
......@@ -247,7 +208,7 @@ describe('CreateIssueForm', () => {
});
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.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