diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-08 06:09:21 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-08 06:09:21 +0300 |
commit | a6db6a23d11a981c6d1fd6b875be863a6c36d934 (patch) | |
tree | 148a9ad5fdf04b511fabe74c7e1ffc41fe92659b /app/assets/javascripts/work_items | |
parent | 00871a937dabdf0a100e465c2820e69b82556898 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/work_items')
-rw-r--r-- | app/assets/javascripts/work_items/components/work_item_assignees.vue | 81 | ||||
-rw-r--r-- | app/assets/javascripts/work_items/graphql/provider.js | 14 |
2 files changed, 66 insertions, 29 deletions
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue index 9ff424aa20f..f1b12e6478f 100644 --- a/app/assets/javascripts/work_items/components/work_item_assignees.vue +++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue @@ -18,11 +18,17 @@ import { n__, s__ } from '~/locale'; import Tracking from '~/tracking'; import SidebarParticipant from '~/sidebar/components/assignees/sidebar_participant.vue'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; -import localUpdateWorkItemMutation from '../graphql/local_update_work_item.mutation.graphql'; +import updateWorkItemMutation from '../graphql/update_work_item.mutation.graphql'; import { i18n, TRACKING_CATEGORY_SHOW } from '../constants'; function isTokenSelectorElement(el) { - return el?.classList.contains('gl-token-close') || el?.classList.contains('dropdown-item'); + return ( + el?.classList.contains('gl-token-close') || + el?.classList.contains('dropdown-item') || + // TODO: replace this logic when we have a class added to clear-all button in GitLab UI + (el?.classList.contains('gl-button') && + el?.closest('.form-control')?.classList.contains('gl-token-selector')) + ); } function addClass(el) { @@ -130,7 +136,7 @@ export default { if (this.searchUsers.some((user) => user.username === this.currentUser.username)) { return this.moveCurrentUserToStart(this.searchUsers); } - return [this.currentUser, ...this.searchUsers]; + return [addClass(this.currentUser), ...this.searchUsers]; } return this.searchUsers; }, @@ -142,12 +148,18 @@ export default { ? s__('WorkItem|Add assignees') : s__('WorkItem|Add assignee'); }, + assigneeIds() { + return this.localAssignees.map(({ id }) => id); + }, }, watch: { - assignees(newVal) { - if (!this.isEditing) { - this.localAssignees = newVal.map(addClass); - } + assignees: { + handler(newVal) { + if (!this.isEditing) { + this.localAssignees = newVal.map(addClass); + } + }, + deep: true, }, }, created() { @@ -169,19 +181,33 @@ export default { handleBlur(e) { if (isTokenSelectorElement(e.relatedTarget) || !this.isEditing) return; this.isEditing = false; - this.setAssignees(this.localAssignees); + this.setAssignees(this.assigneeIds); }, - setAssignees(assignees) { - this.$apollo.mutate({ - mutation: localUpdateWorkItemMutation, - variables: { - input: { - id: this.workItemId, - assignees, + async setAssignees(assigneeIds) { + try { + const { + data: { + workItemUpdate: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: updateWorkItemMutation, + variables: { + input: { + id: this.workItemId, + assigneesWidget: { + assigneeIds, + }, + }, }, - }, - }); - this.track('updated_assignees'); + }); + if (errors.length > 0) { + this.throwUpdateError(); + return; + } + this.track('updated_assignees'); + } catch { + this.throwUpdateError(); + } }, handleFocus() { this.isEditing = true; @@ -205,13 +231,25 @@ export default { }, moveCurrentUserToStart(users = []) { if (this.currentUser) { - return [this.currentUser, ...users.filter((user) => user.id !== this.currentUser.id)]; + return [ + addClass(this.currentUser), + ...users.filter((user) => user.id !== this.currentUser.id), + ]; } return users; }, closeDropdown() { this.$refs.tokenSelector.closeDropdown(); }, + assignToCurrentUser() { + this.setAssignees([this.currentUser.id]); + this.localAssignees = [addClass(this.currentUser)]; + }, + throwUpdateError() { + this.$emit('error', i18n.updateError); + // If mutation is rejected, we're rolling back to initial state + this.localAssignees = this.assignees.map(addClass); + }, }, }; </script> @@ -227,11 +265,12 @@ export default { ref="tokenSelector" :selected-tokens="localAssignees" :container-class="containerClass" - class="assignees-selector gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0!" :class="{ 'gl-hover-border-gray-200': canUpdate }" :dropdown-items="dropdownItems" :loading="isLoadingUsers" :view-only="!canUpdate" + :allow-clear-all="isEditing" + class="assignees-selector gl-flex-grow-1 gl-border gl-border-white gl-rounded-base col-9 gl-align-self-start gl-px-0!" @input="handleAssigneesInput" @text-input="debouncedSearchKeyUpdate" @focus="handleFocus" @@ -251,7 +290,7 @@ export default { size="small" class="assign-myself" data-testid="assign-self" - @click.stop="setAssignees([currentUser])" + @click.stop="assignToCurrentUser" >{{ __('Assign myself') }}</gl-button > </div> diff --git a/app/assets/javascripts/work_items/graphql/provider.js b/app/assets/javascripts/work_items/graphql/provider.js index 1feef8bcaf8..b70c06fddea 100644 --- a/app/assets/javascripts/work_items/graphql/provider.js +++ b/app/assets/javascripts/work_items/graphql/provider.js @@ -2,7 +2,7 @@ import produce from 'immer'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createDefaultClient from '~/lib/graphql'; -import { WIDGET_TYPE_ASSIGNEES, WIDGET_TYPE_LABELS } from '../constants'; +import { WIDGET_TYPE_LABELS } from '../constants'; import typeDefs from './typedefs.graphql'; import workItemQuery from './work_item.query.graphql'; @@ -29,6 +29,11 @@ export const temporaryConfig = { ); }, }, + widgets: { + merge(_, incoming) { + return incoming; + }, + }, }, }, }, @@ -44,13 +49,6 @@ export const resolvers = { }); const data = produce(sourceData, (draftData) => { - if (input.assignees) { - const assigneesWidget = draftData.workItem.widgets.find( - (widget) => widget.type === WIDGET_TYPE_ASSIGNEES, - ); - assigneesWidget.assignees.nodes = [...input.assignees]; - } - if (input.labels) { const labelsWidget = draftData.workItem.mockWidgets.find( (widget) => widget.type === WIDGET_TYPE_LABELS, |