debian-mirror-gitlab/app/assets/javascripts/vue_shared/components/project_selector/project_selector.vue

133 lines
3.4 KiB
Vue
Raw Normal View History

2019-07-07 11:18:12 +05:30
<script>
2020-04-22 19:07:51 +05:30
import { debounce } from 'lodash';
2019-12-26 22:10:19 +05:30
import { GlLoadingIcon, GlSearchBoxByType, GlInfiniteScroll } from '@gitlab/ui';
2020-06-23 00:09:42 +05:30
import { __, n__, sprintf } from '~/locale';
2019-07-07 11:18:12 +05:30
import ProjectListItem from './project_list_item.vue';
const SEARCH_INPUT_TIMEOUT_MS = 500;
export default {
name: 'ProjectSelector',
components: {
GlLoadingIcon,
2019-12-04 20:38:33 +05:30
GlSearchBoxByType,
2019-12-26 22:10:19 +05:30
GlInfiniteScroll,
2019-07-07 11:18:12 +05:30
ProjectListItem,
},
props: {
projectSearchResults: {
type: Array,
required: true,
},
selectedProjects: {
type: Array,
required: true,
},
showNoResultsMessage: {
type: Boolean,
2020-06-23 00:09:42 +05:30
required: true,
2019-07-07 11:18:12 +05:30
},
showMinimumSearchQueryMessage: {
type: Boolean,
2020-06-23 00:09:42 +05:30
required: true,
2019-07-07 11:18:12 +05:30
},
showLoadingIndicator: {
type: Boolean,
2020-06-23 00:09:42 +05:30
required: true,
2019-07-07 11:18:12 +05:30
},
showSearchErrorMessage: {
type: Boolean,
2020-06-23 00:09:42 +05:30
required: true,
2019-07-07 11:18:12 +05:30
},
2019-12-26 22:10:19 +05:30
totalResults: {
type: Number,
2020-06-23 00:09:42 +05:30
required: true,
2019-12-26 22:10:19 +05:30
},
2019-07-07 11:18:12 +05:30
},
data() {
return {
searchQuery: '',
};
},
2020-06-23 00:09:42 +05:30
computed: {
legendText() {
const count = this.projectSearchResults.length;
const total = this.totalResults;
if (total > 0) {
return sprintf(__('Showing %{count} of %{total} projects'), { count, total });
}
return sprintf(n__('Showing %{count} project', 'Showing %{count} projects', count), {
count,
});
},
},
2019-07-07 11:18:12 +05:30
methods: {
projectClicked(project) {
this.$emit('projectClicked', project);
},
2019-12-26 22:10:19 +05:30
bottomReached() {
this.$emit('bottomReached');
},
2019-07-07 11:18:12 +05:30
isSelected(project) {
2020-04-22 19:07:51 +05:30
return this.selectedProjects.some(({ id }) => project.id === id);
2019-07-07 11:18:12 +05:30
},
2020-04-22 19:07:51 +05:30
onInput: debounce(function debouncedOnInput() {
2019-07-07 11:18:12 +05:30
this.$emit('searched', this.searchQuery);
}, SEARCH_INPUT_TIMEOUT_MS),
},
};
</script>
<template>
<div>
2019-12-04 20:38:33 +05:30
<gl-search-box-by-type
2019-07-07 11:18:12 +05:30
v-model="searchQuery"
:placeholder="__('Search your projects')"
type="search"
2019-12-04 20:38:33 +05:30
class="mb-3"
2019-07-07 11:18:12 +05:30
autofocus
@input="onInput"
/>
<div class="d-flex flex-column">
2020-04-22 19:07:51 +05:30
<gl-loading-icon v-if="showLoadingIndicator" size="sm" class="py-2 px-4" />
2019-12-26 22:10:19 +05:30
<gl-infinite-scroll
:max-list-height="402"
:fetched-items="projectSearchResults.length"
:total-items="totalResults"
@bottomReached="bottomReached"
>
2020-06-23 00:09:42 +05:30
<template v-if="!showLoadingIndicator" #items>
<div class="d-flex flex-column">
<project-list-item
v-for="project in projectSearchResults"
:key="project.id"
:selected="isSelected(project)"
:project="project"
:matcher="searchQuery"
class="js-project-list-item"
@click="projectClicked(project)"
/>
</div>
</template>
<template #default>
{{ legendText }}
</template>
2019-12-26 22:10:19 +05:30
</gl-infinite-scroll>
2019-07-07 11:18:12 +05:30
<div v-if="showNoResultsMessage" class="text-muted ml-2 js-no-results-message">
{{ __('Sorry, no projects matched your search') }}
</div>
<div
v-if="showMinimumSearchQueryMessage"
class="text-muted ml-2 js-minimum-search-query-message"
>
{{ __('Enter at least three characters to search') }}
</div>
<div v-if="showSearchErrorMessage" class="text-danger ml-2 js-search-error-message">
{{ __('Something went wrong, unable to search projects') }}
</div>
</div>
</div>
</template>