diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-19 08:27:35 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-19 08:27:35 +0000 |
commit | 7e9c479f7de77702622631cff2628a9c8dcbc627 (patch) | |
tree | c8f718a08e110ad7e1894510980d2155a6549197 /app/assets/javascripts/boards/components/board_assignee_dropdown.vue | |
parent | e852b0ae16db4052c1c567d9efa4facc81146e88 (diff) | |
download | gitlab-ce-7e9c479f7de77702622631cff2628a9c8dcbc627.tar.gz |
Add latest changes from gitlab-org/gitlab@13-6-stable-eev13.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/boards/components/board_assignee_dropdown.vue')
-rw-r--r-- | app/assets/javascripts/boards/components/board_assignee_dropdown.vue | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/app/assets/javascripts/boards/components/board_assignee_dropdown.vue b/app/assets/javascripts/boards/components/board_assignee_dropdown.vue new file mode 100644 index 00000000000..c81f171af2b --- /dev/null +++ b/app/assets/javascripts/boards/components/board_assignee_dropdown.vue @@ -0,0 +1,178 @@ +<script> +import { mapActions, mapGetters } from 'vuex'; +import { + GlDropdownItem, + GlDropdownDivider, + GlAvatarLabeled, + GlAvatarLink, + GlSearchBoxByType, +} from '@gitlab/ui'; +import { __, n__ } from '~/locale'; +import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue'; +import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; +import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue'; +import getIssueParticipants from '~/vue_shared/components/sidebar/queries/getIssueParticipants.query.graphql'; +import searchUsers from '~/boards/queries/users_search.query.graphql'; + +export default { + noSearchDelay: 0, + searchDelay: 250, + i18n: { + unassigned: __('Unassigned'), + assignee: __('Assignee'), + assignees: __('Assignees'), + assignTo: __('Assign to'), + }, + components: { + BoardEditableItem, + IssuableAssignees, + MultiSelectDropdown, + GlDropdownItem, + GlDropdownDivider, + GlAvatarLabeled, + GlAvatarLink, + GlSearchBoxByType, + }, + data() { + return { + search: '', + participants: [], + selected: this.$store.getters.activeIssue.assignees, + }; + }, + apollo: { + participants: { + query() { + return this.isSearchEmpty ? getIssueParticipants : searchUsers; + }, + variables() { + if (this.isSearchEmpty) { + return { + id: `gid://gitlab/Issue/${this.activeIssue.iid}`, + }; + } + + return { + search: this.search, + }; + }, + update(data) { + if (this.isSearchEmpty) { + return data.issue?.participants?.nodes || []; + } + + return data.users?.nodes || []; + }, + debounce() { + const { noSearchDelay, searchDelay } = this.$options; + + return this.isSearchEmpty ? noSearchDelay : searchDelay; + }, + }, + }, + computed: { + ...mapGetters(['activeIssue']), + assigneeText() { + return n__('Assignee', '%d Assignees', this.selected.length); + }, + unSelectedFiltered() { + return this.participants.filter(({ username }) => { + return !this.selectedUserNames.includes(username); + }); + }, + selectedIsEmpty() { + return this.selected.length === 0; + }, + selectedUserNames() { + return this.selected.map(({ username }) => username); + }, + isSearchEmpty() { + return this.search === ''; + }, + }, + methods: { + ...mapActions(['setAssignees']), + clearSelected() { + this.selected = []; + }, + selectAssignee(name) { + if (name === undefined) { + this.clearSelected(); + return; + } + + this.selected = this.selected.concat(name); + }, + unselect(name) { + this.selected = this.selected.filter(user => user.username !== name); + }, + saveAssignees() { + this.setAssignees(this.selectedUserNames); + }, + isChecked(id) { + return this.selectedUserNames.includes(id); + }, + }, +}; +</script> + +<template> + <board-editable-item :title="assigneeText" @close="saveAssignees"> + <template #collapsed> + <issuable-assignees :users="activeIssue.assignees" /> + </template> + + <template #default> + <multi-select-dropdown + class="w-100" + :text="$options.i18n.assignees" + :header-text="$options.i18n.assignTo" + > + <template #search> + <gl-search-box-by-type v-model.trim="search" /> + </template> + <template #items> + <gl-dropdown-item + :is-checked="selectedIsEmpty" + data-testid="unassign" + class="mt-2" + @click="selectAssignee()" + >{{ $options.i18n.unassigned }}</gl-dropdown-item + > + <gl-dropdown-divider data-testid="unassign-divider" /> + <gl-dropdown-item + v-for="item in selected" + :key="item.id" + :is-checked="isChecked(item.username)" + @click="unselect(item.username)" + > + <gl-avatar-link> + <gl-avatar-labeled + :size="32" + :label="item.name" + :sub-label="item.username" + :src="item.avatarUrl || item.avatar" + /> + </gl-avatar-link> + </gl-dropdown-item> + <gl-dropdown-divider v-if="!selectedIsEmpty" data-testid="selected-user-divider" /> + <gl-dropdown-item + v-for="unselectedUser in unSelectedFiltered" + :key="unselectedUser.id" + :data-testid="`item_${unselectedUser.name}`" + @click="selectAssignee(unselectedUser)" + > + <gl-avatar-link> + <gl-avatar-labeled + :size="32" + :label="unselectedUser.name" + :sub-label="unselectedUser.username" + :src="unselectedUser.avatarUrl || unselectedUser.avatar" + /> + </gl-avatar-link> + </gl-dropdown-item> + </template> + </multi-select-dropdown> + </template> + </board-editable-item> +</template> |