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:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-11-05 21:08:48 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-11-05 21:08:48 +0300
commit3e1c760141a27097d74d191a619fa6edecd86fe7 (patch)
treedc26e1842b355d2ebad6c8923077b0a016aa82c9 /app/assets/javascripts/invite_members
parent74dd67ddea70f70830f3fe1ca65b06b604ec229f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/invite_members')
-rw-r--r--app/assets/javascripts/invite_members/components/invite_members_modal.vue49
-rw-r--r--app/assets/javascripts/invite_members/components/members_token_select.vue120
-rw-r--r--app/assets/javascripts/invite_members/constants.js1
3 files changed, 148 insertions, 22 deletions
diff --git a/app/assets/javascripts/invite_members/components/invite_members_modal.vue b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
index d2ea14a658b..b47b22c4d44 100644
--- a/app/assets/javascripts/invite_members/components/invite_members_modal.vue
+++ b/app/assets/javascripts/invite_members/components/invite_members_modal.vue
@@ -6,13 +6,13 @@ import {
GlDatepicker,
GlLink,
GlSprintf,
- GlSearchBoxByType,
GlButton,
GlFormInput,
} from '@gitlab/ui';
import eventHub from '../event_hub';
import { s__, sprintf } from '~/locale';
import Api from '~/api';
+import MembersTokenSelect from '~/invite_members/components/members_token_select.vue';
export default {
name: 'InviteMembersModal',
@@ -23,9 +23,9 @@ export default {
GlDropdown,
GlDropdownItem,
GlSprintf,
- GlSearchBoxByType,
GlButton,
GlFormInput,
+ MembersTokenSelect,
},
props: {
groupId: {
@@ -129,44 +129,45 @@ export default {
},
labels: {
modalTitle: s__('InviteMembersModal|Invite team members'),
- userToInvite: s__('InviteMembersModal|GitLab member or Email address'),
+ newUsersToInvite: s__('InviteMembersModal|GitLab member or Email address'),
userPlaceholder: s__('InviteMembersModal|Search for members to invite'),
accessLevel: s__('InviteMembersModal|Choose a role permission'),
accessExpireDate: s__('InviteMembersModal|Access expiration date (optional)'),
- toastMessageSuccessful: s__('InviteMembersModal|Users were succesfully added'),
- toastMessageUnsuccessful: s__('InviteMembersModal|User not invited. Feature coming soon!'),
+ toastMessageSuccessful: s__('InviteMembersModal|Members were successfully added'),
+ toastMessageUnsuccessful: s__('InviteMembersModal|Some of the members could not be added'),
readMoreText: s__(`InviteMembersModal|%{linkStart}Read more%{linkEnd} about role permissions`),
inviteButtonText: s__('InviteMembersModal|Invite'),
cancelButtonText: s__('InviteMembersModal|Cancel'),
+ headerCloseLabel: s__('InviteMembersModal|Close invite team members'),
},
+ membersTokenSelectLabelId: 'invite-members-input',
};
</script>
<template>
- <gl-modal :modal-id="modalId" size="sm" :title="$options.labels.modalTitle">
+ <gl-modal
+ :modal-id="modalId"
+ size="sm"
+ :title="$options.labels.modalTitle"
+ :header-close-label="$options.labels.headerCloseLabel"
+ >
<div class="gl-ml-5 gl-mr-5">
<div>{{ introText }}</div>
- <label class="gl-font-weight-bold gl-mt-5">{{ $options.labels.userToInvite }}</label>
+ <label :id="$options.membersTokenSelectLabelId" class="gl-font-weight-bold gl-mt-5">{{
+ $options.labels.newUsersToInvite
+ }}</label>
<div class="gl-mt-2">
- <gl-search-box-by-type
+ <members-token-select
v-model="newUsersToInvite"
+ :label="$options.labels.newUsersToInvite"
+ :aria-labelledby="$options.membersTokenSelectLabelId"
:placeholder="$options.labels.userPlaceholder"
- type="text"
- autocomplete="off"
- autocorrect="off"
- autocapitalize="off"
- spellcheck="false"
/>
</div>
<label class="gl-font-weight-bold gl-mt-5">{{ $options.labels.accessLevel }}</label>
<div class="gl-mt-2 gl-w-half gl-xs-w-full">
- <gl-dropdown
- menu-class="dropdown-menu-selectable"
- class="gl-shadow-none gl-w-full"
- v-bind="$attrs"
- :text="selectedRoleName"
- >
+ <gl-dropdown class="gl-shadow-none gl-w-full" v-bind="$attrs" :text="selectedRoleName">
<template v-for="(key, item) in accessLevels">
<gl-dropdown-item
:key="key"
@@ -215,9 +216,13 @@ export default {
{{ $options.labels.cancelButtonText }}
</gl-button>
<div class="gl-mr-3"></div>
- <gl-button ref="inviteButton" variant="success" @click="sendInvite">{{
- $options.labels.inviteButtonText
- }}</gl-button>
+ <gl-button
+ ref="inviteButton"
+ :disabled="!newUsersToInvite"
+ variant="success"
+ @click="sendInvite"
+ >{{ $options.labels.inviteButtonText }}</gl-button
+ >
</div>
</template>
</gl-modal>
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>
diff --git a/app/assets/javascripts/invite_members/constants.js b/app/assets/javascripts/invite_members/constants.js
new file mode 100644
index 00000000000..1ff2125c292
--- /dev/null
+++ b/app/assets/javascripts/invite_members/constants.js
@@ -0,0 +1 @@
+export const USER_SEARCH_DELAY = 200;