diff options
Diffstat (limited to 'app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue')
-rw-r--r-- | app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue | 210 |
1 files changed, 73 insertions, 137 deletions
diff --git a/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue index 34a4da946d6..ea8e0c4b950 100644 --- a/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue +++ b/app/assets/javascripts/sidebar/components/move/issuable_move_dropdown.vue @@ -1,26 +1,20 @@ <script> import { GlIcon, - GlLoadingIcon, - GlDropdown, - GlDropdownForm, - GlDropdownItem, - GlSearchBoxByType, GlButton, + GlCollapsibleListbox, GlTooltipDirective as GlTooltip, } from '@gitlab/ui'; - +import { debounce } from 'lodash'; +import { __ } from '~/locale'; +import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import axios from '~/lib/utils/axios_utils'; export default { components: { GlIcon, - GlLoadingIcon, - GlDropdown, - GlDropdownForm, - GlDropdownItem, - GlSearchBoxByType, GlButton, + GlCollapsibleListbox, }, directives: { GlTooltip, @@ -51,82 +45,58 @@ export default { }, data() { return { - projectsListLoading: false, - projectsListLoadFailed: false, - searchKey: '', projects: [], - selectedProject: null, - projectItemClick: false, + projectsList: [], + selectedProjects: [], + noResultsText: '', + isSearching: 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); - }, + mounted() { + this.fetchProjects = debounce(this.fetchProjects, DEFAULT_DEBOUNCE_AND_THROTTLE_MS); }, methods: { - fetchProjects(search = '') { - this.projectsListLoading = true; - this.projectsListLoadFailed = false; - return axios - .get(this.projectsFetchPath, { + triggerSearch() { + this.$refs.dropdown.search(); + }, + async fetchProjects(search = '') { + this.isSearching = true; + + try { + const { data } = await 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'); + this.projects = data; + this.projectsList = data.map((item) => ({ + value: item.id, + text: item.name_with_namespace, + })); + + if (!this.projectsList.length) { + this.noResultsText = __('No matching results'); + } + } catch (e) { + this.noResultsText = __('Failed to load projects'); + } finally { + this.isSearching = false; } }, - handleDropdownCloseClick() { - this.$refs.dropdown.hide(); - }, - handleProjectSelect(project) { - this.selectedProject = project.id === this.selectedProject?.id ? null : project; - this.projectItemClick = true; + handleProjectSelect(items) { + // hack: simulate a single select to prevent the dropdown from closing + // todo: switch back to single select when https://gitlab.com/gitlab-org/gitlab-ui/-/issues/2363 is fixed + this.selectedProjects = [items[items.length - 1]]; }, handleMoveClick() { - this.$refs.dropdown.hide(); - this.$emit('move-issuable', this.selectedProject); + this.$refs.dropdown.close(); + this.$emit( + 'move-issuable', + this.projects.find((item) => item.id === this.selectedProjects[0]), + ); + }, + handleDropdownHide() { + this.$emit('dropdown-close'); }, }, }; @@ -143,79 +113,45 @@ export default { > <gl-icon name="arrow-right" /> </div> - <gl-dropdown + <gl-collapsible-listbox ref="dropdown" + v-model="selectedProjects" + :items="projectsList" :block="true" - :disabled="moveInProgress || disabled" - class="hide-collapsed" - toggle-class="js-sidebar-dropdown-toggle" - @shown="fetchProjects" - @hide="handleDropdownHide" + :multiple="true" + :searchable="true" + :searching="isSearching" + :search-placeholder="__('Search project')" + :no-results-text="noResultsText" + :header-text="dropdownButtonTitle" + @hidden="handleDropdownHide" + @shown="triggerSearch" + @search="fetchProjects" + @select="handleProjectSelect" > - <template #button-content - ><gl-loading-icon v-if="moveInProgress" size="sm" 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!" - :aria-label="__('Close')" - @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="lg" class="gl-p-5" /> - <ul v-else> - <gl-dropdown-item - v-for="project in projects" - :key="project.id" - is-check-item - :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" - data-testid="failed-load-results" - 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" + <template #toggle> + <gl-button + :loading="moveInProgress" + size="medium" + class="gl-w-full js-sidebar-dropdown-toggle hide-collapsed" + data-testid="dropdown-button" + :disabled="moveInProgress || disabled" + >{{ dropdownButtonTitle }}</gl-button > + </template> + <template #footer> + <div data-testid="footer" class="gl-p-3"> <gl-button category="primary" variant="confirm" - :disabled="!Boolean(selectedProject)" - class="gl-w-full issuable-move-button" + :disabled="!Boolean(selectedProjects.length)" + class="gl-w-full" + data-testid="dropdown-move-button" @click="handleMoveClick" >{{ __('Move') }}</gl-button > </div> - </gl-dropdown-form> - </gl-dropdown> + </template> + </gl-collapsible-listbox> </div> </template> |