diff options
Diffstat (limited to 'app/assets/javascripts/invite_members/components/members_token_select.vue')
-rw-r--r-- | app/assets/javascripts/invite_members/components/members_token_select.vue | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/app/assets/javascripts/invite_members/components/members_token_select.vue b/app/assets/javascripts/invite_members/components/members_token_select.vue new file mode 100644 index 00000000000..aed2e5e3236 --- /dev/null +++ b/app/assets/javascripts/invite_members/components/members_token_select.vue @@ -0,0 +1,120 @@ +<script> +import { debounce } from 'lodash'; +import { GlTokenSelector, GlAvatar, GlAvatarLabeled } from '@gitlab/ui'; +import { USER_SEARCH_DELAY } from '../constants'; +import Api from '~/api'; + +export default { + components: { + GlTokenSelector, + GlAvatar, + GlAvatarLabeled, + }, + props: { + placeholder: { + type: String, + required: false, + default: '', + }, + ariaLabelledby: { + type: String, + required: true, + }, + }, + data() { + return { + loading: false, + query: '', + users: [], + selectedTokens: [], + hasBeenFocused: false, + hideDropdownWithNoItems: true, + }; + }, + computed: { + newUsersToInvite() { + return this.selectedTokens + .map(obj => { + return obj.id; + }) + .join(','); + }, + placeholderText() { + if (this.selectedTokens.length === 0) { + return this.placeholder; + } + return ''; + }, + }, + methods: { + handleTextInput(query) { + this.hideDropdownWithNoItems = false; + this.query = query; + this.loading = true; + this.retrieveUsers(query); + }, + retrieveUsers: debounce(function debouncedRetrieveUsers() { + return Api.users(this.query, this.$options.queryOptions) + .then(response => { + this.users = response.data.map(token => ({ + id: token.id, + name: token.name, + username: token.username, + avatar_url: token.avatar_url, + })); + this.loading = false; + }) + .catch(() => { + this.loading = false; + }); + }, USER_SEARCH_DELAY), + handleInput() { + this.$emit('input', this.newUsersToInvite); + }, + handleBlur() { + this.hideDropdownWithNoItems = false; + }, + handleFocus() { + // The modal auto-focuses on the input when opened. + // This prevents the dropdown from opening when the modal opens. + if (this.hasBeenFocused) { + this.loading = true; + this.retrieveUsers(); + } + + this.hasBeenFocused = true; + }, + }, + queryOptions: { exclude_internal: true, active: true }, +}; +</script> + +<template> + <gl-token-selector + v-model="selectedTokens" + :dropdown-items="users" + :loading="loading" + :allow-user-defined-tokens="false" + :hide-dropdown-with-no-items="hideDropdownWithNoItems" + :placeholder="placeholderText" + :aria-labelledby="ariaLabelledby" + @blur="handleBlur" + @text-input="handleTextInput" + @input="handleInput" + @focus="handleFocus" + > + <template #token-content="{ token }"> + <gl-avatar v-if="token.avatar_url" :src="token.avatar_url" :size="16" /> + {{ token.name }} + </template> + + <template #dropdown-item-content="{ dropdownItem }"> + <gl-avatar-labeled + :src="dropdownItem.avatar_url" + :size="32" + :label="dropdownItem.name" + :sub-label="dropdownItem.username" + /> + </template> + </gl-token-selector> +</template> |