Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/boards/components/project_select.vue')
-rw-r--r--app/assets/javascripts/boards/components/project_select.vue193
1 files changed, 107 insertions, 86 deletions
diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue
index 9c90938fc52..04699d0d3a4 100644
--- a/app/assets/javascripts/boards/components/project_select.vue
+++ b/app/assets/javascripts/boards/components/project_select.vue
@@ -1,120 +1,141 @@
<script>
-import $ from 'jquery';
-import { escape } from 'lodash';
-import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
-import { __ } from '~/locale';
-import eventHub from '../eventhub';
-import Api from '../../api';
+import { mapActions, mapState } from 'vuex';
+import {
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlSearchBoxByType,
+ GlIntersectionObserver,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import { s__ } from '~/locale';
import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
-import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
import { ListType } from '../constants';
export default {
- name: 'BoardProjectSelect',
+ name: 'ProjectSelect',
+ i18n: {
+ headerTitle: s__(`BoardNewIssue|Projects`),
+ dropdownText: s__(`BoardNewIssue|Select a project`),
+ searchPlaceholder: s__(`BoardNewIssue|Search projects`),
+ emptySearchResult: s__(`BoardNewIssue|No matching results`),
+ },
+ defaultFetchOptions: {
+ with_issues_enabled: true,
+ with_shared: false,
+ include_subgroups: true,
+ order_by: 'similarity',
+ },
components: {
- GlIcon,
+ GlIntersectionObserver,
GlLoadingIcon,
+ GlDropdown,
+ GlDropdownItem,
+ GlDropdownText,
+ GlSearchBoxByType,
},
+ inject: ['groupId'],
props: {
list: {
type: Object,
required: true,
},
},
- inject: ['groupId'],
data() {
return {
- loading: true,
+ initialLoading: true,
selectedProject: {},
+ searchTerm: '',
};
},
computed: {
+ ...mapState(['groupProjects', 'groupProjectsFlags']),
selectedProjectName() {
- return this.selectedProject.name || __('Select a project');
+ return this.selectedProject.name || this.$options.i18n.dropdownText;
+ },
+ fetchOptions() {
+ const additionalAttrs = {};
+ if (this.list.type && this.list.type !== ListType.backlog) {
+ additionalAttrs.min_access_level = featureAccessLevel.EVERYONE;
+ }
+
+ return {
+ ...this.$options.defaultFetchOptions,
+ ...additionalAttrs,
+ };
+ },
+ isFetchResultEmpty() {
+ return this.groupProjects.length === 0;
+ },
+ hasNextPage() {
+ return this.groupProjectsFlags.pageInfo?.hasNextPage;
+ },
+ },
+ watch: {
+ searchTerm() {
+ this.fetchGroupProjects({ search: this.searchTerm });
},
},
mounted() {
- initDeprecatedJQueryDropdown($(this.$refs.projectsDropdown), {
- filterable: true,
- filterRemote: true,
- search: {
- fields: ['name_with_namespace'],
- },
- clicked: ({ $el, e }) => {
- e.preventDefault();
- this.selectedProject = {
- id: $el.data('project-id'),
- name: $el.data('project-name'),
- path: $el.data('project-path'),
- };
- eventHub.$emit('setSelectedProject', this.selectedProject);
- },
- selectable: true,
- data: (term, callback) => {
- this.loading = true;
- const additionalAttrs = {};
+ this.fetchGroupProjects({});
- if ((this.list.type || this.list.listType) !== ListType.backlog) {
- additionalAttrs.min_access_level = featureAccessLevel.EVERYONE;
- }
-
- return Api.groupProjects(
- this.groupId,
- term,
- {
- with_issues_enabled: true,
- with_shared: false,
- include_subgroups: true,
- order_by: 'similarity',
- ...additionalAttrs,
- },
- projects => {
- this.loading = false;
- callback(projects);
- },
- );
- },
- renderRow(project) {
- return `
- <li>
- <a href='#' class='dropdown-menu-link'
- data-project-id="${project.id}"
- data-project-name="${project.name}"
- data-project-name-with-namespace="${project.name_with_namespace}"
- data-project-path="${project.path_with_namespace}"
- >
- ${escape(project.name_with_namespace)}
- </a>
- </li>
- `;
- },
- text: project => project.name_with_namespace,
- });
+ this.initialLoading = false;
+ },
+ methods: {
+ ...mapActions(['fetchGroupProjects', 'setSelectedProject']),
+ selectProject(projectId) {
+ this.selectedProject = this.groupProjects.find((project) => project.id === projectId);
+ this.setSelectedProject(this.selectedProject);
+ },
+ loadMoreProjects() {
+ this.fetchGroupProjects({ search: this.searchTerm, fetchNext: true });
+ },
},
};
</script>
<template>
<div>
- <label class="label-bold gl-mt-3">{{ __('Project') }}</label>
- <div ref="projectsDropdown" class="dropdown dropdown-projects">
- <button
- class="dropdown-menu-toggle wide"
- type="button"
- data-toggle="dropdown"
- aria-expanded="false"
+ <label class="gl-font-weight-bold gl-mt-3" data-testid="header-label">{{
+ $options.i18n.headerTitle
+ }}</label>
+ <gl-dropdown
+ data-testid="project-select-dropdown"
+ :text="selectedProjectName"
+ :header-text="$options.i18n.headerTitle"
+ block
+ menu-class="gl-w-full!"
+ :loading="initialLoading"
+ >
+ <gl-search-box-by-type
+ v-model.trim="searchTerm"
+ debounce="250"
+ :placeholder="$options.i18n.searchPlaceholder"
+ />
+ <gl-dropdown-item
+ v-for="project in groupProjects"
+ v-show="!groupProjectsFlags.isLoading"
+ :key="project.id"
+ :name="project.name"
+ @click="selectProject(project.id)"
+ >
+ {{ project.nameWithNamespace }}
+ </gl-dropdown-item>
+ <gl-dropdown-text
+ v-show="groupProjectsFlags.isLoading"
+ data-testid="dropdown-text-loading-icon"
+ >
+ <gl-loading-icon class="gl-mx-auto" />
+ </gl-dropdown-text>
+ <gl-dropdown-text
+ v-if="isFetchResultEmpty && !groupProjectsFlags.isLoading"
+ data-testid="empty-result-message"
>
- {{ selectedProjectName }} <gl-icon name="chevron-down" class="dropdown-menu-toggle-icon" />
- </button>
- <div class="dropdown-menu dropdown-menu-selectable dropdown-menu-full-width">
- <div class="dropdown-title">{{ __('Projects') }}</div>
- <div class="dropdown-input">
- <input class="dropdown-input-field" type="search" :placeholder="__('Search projects')" />
- <gl-icon name="search" class="dropdown-input-search" data-hidden="true" />
- </div>
- <div class="dropdown-content"></div>
- <div class="dropdown-loading"><gl-loading-icon /></div>
- </div>
- </div>
+ <span class="gl-text-gray-500">{{ $options.i18n.emptySearchResult }}</span>
+ </gl-dropdown-text>
+ <gl-intersection-observer v-if="hasNextPage" @appear="loadMoreProjects">
+ <gl-loading-icon v-if="groupProjectsFlags.isLoadingMore" size="md" />
+ </gl-intersection-observer>
+ </gl-dropdown>
</div>
</template>