Commit e75cbceb authored by Kushal Pandya's avatar Kushal Pandya

Add Issuable Move dropdown component

Adds Issuable Move dropdown component to
use with Issuable Sidebars
parent ac0709f4
<script>
import {
GlIcon,
GlLoadingIcon,
GlDropdown,
GlDropdownForm,
GlDropdownItem,
GlSearchBoxByType,
GlButton,
GlTooltipDirective as GlTooltip,
} from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
export default {
components: {
GlIcon,
GlLoadingIcon,
GlDropdown,
GlDropdownForm,
GlDropdownItem,
GlSearchBoxByType,
GlButton,
},
directives: {
GlTooltip,
},
props: {
projectsFetchPath: {
type: String,
required: true,
},
dropdownButtonTitle: {
type: String,
required: true,
},
dropdownHeaderTitle: {
type: String,
required: true,
},
moveInProgress: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
projectsListLoading: false,
projectsListLoadFailed: false,
searchKey: '',
projects: [],
selectedProject: null,
projectItemClick: false,
};
},
computed: {
hasNoSearchResults() {
return Boolean(
!this.projectsListLoading &&
!this.projectsListLoadFailed &&
this.searchKey &&
!this.projects.length,
);
},
failedToLoadResults() {
return !this.projectsListLoading && this.projectsListLoadFailed;
},
},
watch: {
searchKey(value = '') {
this.fetchProjects(value);
},
},
methods: {
fetchProjects(search = '') {
this.projectsListLoading = true;
this.projectsListLoadFailed = false;
return axios
.get(this.projectsFetchPath, {
params: {
search,
},
})
.then(({ data }) => {
this.projects = data;
this.$refs.searchInput.focusInput();
})
.catch(() => {
this.projectsListLoadFailed = true;
})
.finally(() => {
this.projectsListLoading = false;
});
},
isSelectedProject(project) {
if (this.selectedProject) {
return this.selectedProject.id === project.id;
}
return false;
},
/**
* This handler is to prevent dropdown
* from closing when an item is selected
* and emit an event only when dropdown closes.
*/
handleDropdownHide(e) {
if (this.projectItemClick) {
e.preventDefault();
this.projectItemClick = false;
} else {
this.$emit('dropdown-close');
}
},
handleDropdownCloseClick() {
this.$refs.dropdown.hide();
},
handleProjectSelect(project) {
this.selectedProject = project.id === this.selectedProject?.id ? null : project;
this.projectItemClick = true;
},
handleMoveClick() {
this.$refs.dropdown.hide();
this.$emit('move-issuable', this.selectedProject);
},
},
};
</script>
<template>
<div class="block js-issuable-move-block issuable-move-dropdown sidebar-move-issue-dropdown">
<div
v-gl-tooltip.left.viewport
data-testid="move-collapsed"
:title="dropdownButtonTitle"
class="sidebar-collapsed-icon"
@click="$emit('toggle-collapse')"
>
<gl-icon name="arrow-right" />
</div>
<gl-dropdown
ref="dropdown"
:block="true"
:disabled="moveInProgress"
class="hide-collapsed"
toggle-class="js-sidebar-dropdown-toggle"
@shown="fetchProjects"
@hide="handleDropdownHide"
>
<template #button-content
><gl-loading-icon v-if="moveInProgress" class="gl-mr-3" />{{
dropdownButtonTitle
}}</template
>
<gl-dropdown-form class="gl-pt-0">
<div
data-testid="header"
class="gl-display-flex gl-pb-3 gl-border-1 gl-border-b-solid gl-border-gray-100"
>
<span class="gl-flex-grow-1 gl-text-center gl-font-weight-bold gl-py-1">{{
dropdownHeaderTitle
}}</span>
<gl-button
variant="link"
icon="close"
class="gl-mr-2 gl-w-auto! gl-p-2!"
@click.prevent="handleDropdownCloseClick"
/>
</div>
<gl-search-box-by-type
ref="searchInput"
v-model.trim="searchKey"
:placeholder="__('Search project')"
:debounce="300"
/>
<div data-testid="content" class="dropdown-content">
<gl-loading-icon v-if="projectsListLoading" size="md" class="gl-p-5" />
<ul v-else>
<gl-dropdown-item
v-for="project in projects"
:key="project.id"
:is-check-item="true"
:is-checked="isSelectedProject(project)"
@click.stop.prevent="handleProjectSelect(project)"
>{{ project.name_with_namespace }}</gl-dropdown-item
>
</ul>
<div v-if="hasNoSearchResults" class="gl-text-center gl-p-3">
{{ __('No matching results') }}
</div>
<div v-if="failedToLoadResults" class="gl-text-center gl-p-3">
{{ __('Failed to load projects') }}
</div>
</div>
<div
data-testid="footer"
class="gl-pt-3 gl-px-3 gl-border-1 gl-border-t-solid gl-border-gray-100"
>
<gl-button
category="primary"
variant="success"
:disabled="!Boolean(selectedProject)"
class="gl-text-center! issuable-move-button"
@click="handleMoveClick"
>{{ __('Move') }}</gl-button
>
</div>
</gl-dropdown-form>
</gl-dropdown>
</div>
</template>
......@@ -921,6 +921,25 @@
}
}
/*
* Following overrides are done to prevent
* legacy dropdown styles from influencing
* GitLab UI components used within GlDropdown
*/
.issuable-move-dropdown {
.b-dropdown-form {
@include gl-p-0;
}
.gl-search-box-by-type button.gl-clear-icon-button:hover {
@include gl-bg-transparent;
}
.issuable-move-button:not(.disabled):hover {
@include gl-text-white;
}
}
.right-sidebar-collapsed {
.sidebar-grouped-item {
.sidebar-collapsed-icon {
......
......@@ -11139,6 +11139,9 @@ msgstr ""
msgid "Failed to load milestones. Please try again."
msgstr ""
msgid "Failed to load projects"
msgstr ""
msgid "Failed to load related branches"
msgstr ""
......
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