diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 09:55:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-07-20 09:55:51 +0000 |
commit | e8d2c2579383897a1dd7f9debd359abe8ae8373d (patch) | |
tree | c42be41678c2586d49a75cabce89322082698334 /app/assets/javascripts/sidebar | |
parent | fc845b37ec3a90aaa719975f607740c22ba6a113 (diff) | |
download | gitlab-ce-e8d2c2579383897a1dd7f9debd359abe8ae8373d.tar.gz |
Add latest changes from gitlab-org/gitlab@14-1-stable-eev14.1.0-rc42
Diffstat (limited to 'app/assets/javascripts/sidebar')
35 files changed, 573 insertions, 56 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue index adb573db652..4b3b22f6db3 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue @@ -47,7 +47,7 @@ export default { <template> <div class="hide-collapsed gl-line-height-20 gl-mb-2 gl-text-gray-900"> {{ assigneeTitle }} - <gl-loading-icon v-if="loading" inline class="align-bottom" /> + <gl-loading-icon v-if="loading" size="sm" inline class="align-bottom" /> <a v-if="editable" class="js-sidebar-dropdown-toggle edit-link float-right" diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue index 9840aa4ed66..c6877226b7d 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue @@ -1,6 +1,6 @@ <script> import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; -import { deprecatedCreateFlash as Flash } from '~/flash'; +import createFlash from '~/flash'; import { __ } from '~/locale'; import eventHub from '~/sidebar/event_hub'; import Store from '~/sidebar/stores/sidebar_store'; @@ -113,7 +113,9 @@ export default { }) .catch(() => { this.loading = false; - return new Flash(__('Error occurred when saving assignees')); + return createFlash({ + message: __('Error occurred when saving assignees'), + }); }); }, exposeAvailabilityStatus(users) { diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue index d9a974202a3..1dd05d3886e 100644 --- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue +++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees_widget.vue @@ -3,6 +3,7 @@ import { GlDropdownItem } from '@gitlab/ui'; import { cloneDeep } from 'lodash'; import Vue from 'vue'; import createFlash from '~/flash'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { IssuableType } from '~/issue_show/constants'; import { __, n__ } from '~/locale'; import SidebarAssigneesRealtime from '~/sidebar/components/assignees/assignees_realtime.vue'; @@ -80,6 +81,8 @@ export default { selected: [], isSettingAssignees: false, isDirty: false, + oldIid: null, + oldSelected: null, }; }, apollo: { @@ -142,6 +145,14 @@ export default { return this.currentUser.username !== undefined; }, }, + watch: { + iid(_, oldIid) { + if (this.isDirty) { + this.oldIid = oldIid; + this.oldSelected = this.selected; + } + }, + }, created() { assigneesWidget.updateAssignees = this.updateAssignees; }, @@ -157,10 +168,14 @@ export default { variables: { ...this.queryVariables, assigneeUsernames, + iid: this.oldIid || this.iid, }, }) .then(({ data }) => { - this.$emit('assignees-updated', data.issuableSetAssignees.issuable.assignees.nodes); + this.$emit('assignees-updated', { + id: getIdFromGraphQLId(data.issuableSetAssignees.issuable.id), + assignees: data.issuableSetAssignees.issuable.assignees.nodes, + }); return data; }) .catch(() => { @@ -176,7 +191,10 @@ export default { saveAssignees() { if (this.isDirty) { this.isDirty = false; - this.updateAssignees(this.selected.map(({ username }) => username)); + const usernames = this.oldSelected || this.selected; + this.updateAssignees(usernames.map(({ username }) => username)); + this.oldIid = null; + this.oldSelected = null; } this.$el.dispatchEvent(hideDropdownEvent); }, diff --git a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue index 41b3b6c9a45..bed84dc5706 100644 --- a/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue +++ b/app/assets/javascripts/sidebar/components/assignees/user_name_with_status.vue @@ -22,8 +22,16 @@ export default { required: false, default: '', }, + pronouns: { + type: String, + required: false, + default: '', + }, }, computed: { + hasPronouns() { + return this.pronouns !== null && this.pronouns.trim() !== ''; + }, isBusy() { return isUserBusy(this.availability); }, @@ -32,9 +40,18 @@ export default { </script> <template> <span :class="containerClasses"> - <gl-sprintf v-if="isBusy" :message="s__('UserAvailability|%{author} (Busy)')"> - <template #author>{{ name }}</template> + <gl-sprintf :message="s__('UserAvailability|%{author} %{spanStart}(Busy)%{spanEnd}')"> + <template #author + >{{ name }} + <span v-if="hasPronouns" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal" + >({{ pronouns }})</span + ></template + > + <template #span="{ content }" + ><span v-if="isBusy" class="gl-text-gray-500 gl-font-sm gl-font-weight-normal">{{ + content + }}</span> + </template> </gl-sprintf> - <template v-else>{{ name }}</template> </span> </template> diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue index 372368707af..dc0f2b54a7b 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue @@ -4,7 +4,7 @@ import Vue from 'vue'; import createFlash from '~/flash'; import { __, sprintf } from '~/locale'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; -import { confidentialityQueries } from '~/sidebar/constants'; +import { confidentialityQueries, Tracking } from '~/sidebar/constants'; import SidebarConfidentialityContent from './sidebar_confidentiality_content.vue'; import SidebarConfidentialityForm from './sidebar_confidentiality_form.vue'; @@ -18,8 +18,8 @@ const hideDropdownEvent = new CustomEvent('hiddenGlDropdown', { export default { tracking: { - event: 'click_edit_button', - label: 'right_sidebar', + event: Tracking.editEvent, + label: Tracking.rightSidebarLabel, property: 'confidentiality', }, components: { diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue index c3dfa5f8b14..1ff24dec884 100644 --- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue +++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue @@ -5,7 +5,13 @@ import { IssuableType } from '~/issue_show/constants'; import { dateInWords, formatDate, parsePikadayDate } from '~/lib/utils/datetime_utility'; import { __, sprintf } from '~/locale'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; -import { dateFields, dateTypes, dueDateQueries, startDateQueries } from '~/sidebar/constants'; +import { + dateFields, + dateTypes, + dueDateQueries, + startDateQueries, + Tracking, +} from '~/sidebar/constants'; import SidebarFormattedDate from './sidebar_formatted_date.vue'; import SidebarInheritDate from './sidebar_inherit_date.vue'; @@ -15,8 +21,8 @@ const hideDropdownEvent = new CustomEvent('hiddenGlDropdown', { export default { tracking: { - event: 'click_edit_button', - label: 'right_sidebar', + event: Tracking.editEvent, + label: Tracking.rightSidebarLabel, }, directives: { GlTooltip: GlTooltipDirective, @@ -149,6 +155,9 @@ export default { }, }, methods: { + epicDatePopoverEl() { + return this.$refs?.epicDatePopover?.$el; + }, closeForm() { this.$refs.editable.collapse(); this.$el.dispatchEvent(hideDropdownEvent); @@ -249,12 +258,7 @@ export default { :aria-label="$options.i18n.help" data-testid="inherit-date-popover" /> - <gl-popover - :target="() => $refs.epicDatePopover.$el" - triggers="focus" - placement="left" - boundary="viewport" - > + <gl-popover :target="epicDatePopoverEl" triggers="focus" placement="left" boundary="viewport"> <p>{{ $options.i18n.dateHelpValidMessage }}</p> <gl-link :href="$options.dateHelpUrl" target="_blank">{{ $options.i18n.learnMore diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue index c3f31a3d220..42d2e456a07 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue @@ -2,7 +2,7 @@ import { GlButton } from '@gitlab/ui'; import $ from 'jquery'; import { mapActions } from 'vuex'; -import { deprecatedCreateFlash as Flash } from '~/flash'; +import createFlash from '~/flash'; import { __, sprintf } from '../../../locale'; import eventHub from '../../event_hub'; @@ -52,7 +52,9 @@ export default { const flashMessage = __( 'Something went wrong trying to change the locked state of this %{issuableDisplayName}', ); - Flash(sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName })); + createFlash({ + message: sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName }), + }); }) .finally(() => { this.closeForm(); diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue index e85e416881c..650aa603f18 100644 --- a/app/assets/javascripts/sidebar/components/participants/participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/participants.vue @@ -92,11 +92,11 @@ export default { @click="onClickCollapsedIcon" > <gl-icon name="users" /> - <gl-loading-icon v-if="loading" /> + <gl-loading-icon v-if="loading" size="sm" /> <span v-else data-testid="collapsed-count"> {{ participantCount }} </span> </div> <div v-if="showParticipantLabel" class="title hide-collapsed gl-mb-2"> - <gl-loading-icon v-if="loading" :inline="true" /> + <gl-loading-icon v-if="loading" size="sm" :inline="true" /> {{ participantLabel }} </div> <div class="participants-list hide-collapsed"> diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue index 88c0b18ccc7..295027186cc 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/reviewer_title.vue @@ -35,7 +35,7 @@ export default { <template> <div class="hide-collapsed gl-line-height-20 gl-mb-2 gl-text-gray-900"> {{ reviewerTitle }} - <gl-loading-icon v-if="loading" inline class="align-bottom" /> + <gl-loading-icon v-if="loading" size="sm" inline class="align-bottom" /> <a v-if="editable" class="js-sidebar-dropdown-toggle edit-link float-right" diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue index c0bd54c60da..e414aaf719b 100644 --- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue +++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue @@ -2,7 +2,7 @@ // NOTE! For the first iteration, we are simply copying the implementation of Assignees // It will soon be overhauled in Issue https://gitlab.com/gitlab-org/gitlab/-/issues/233736 import { refreshUserMergeRequestCounts } from '~/commons/nav/user_merge_requests'; -import { deprecatedCreateFlash as Flash } from '~/flash'; +import createFlash from '~/flash'; import { __ } from '~/locale'; import eventHub from '~/sidebar/event_hub'; import Store from '~/sidebar/stores/sidebar_store'; @@ -80,7 +80,9 @@ export default { }) .catch(() => { this.loading = false; - return new Flash(__('Error occurred when saving reviewers')); + return createFlash({ + message: __('Error occurred when saving reviewers'), + }); }); }, requestReview(data) { diff --git a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue index 592cfea5e32..fdf63c23552 100644 --- a/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue +++ b/app/assets/javascripts/sidebar/components/severity/sidebar_severity.vue @@ -181,7 +181,7 @@ export default { </gl-dropdown-item> </gl-dropdown> - <gl-loading-icon v-if="isUpdating" :inline="true" /> + <gl-loading-icon v-if="isUpdating" size="sm" :inline="true" /> <severity-token v-else-if="!isDropdownShowing" :severity="selectedItem" /> </div> diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index c80ccc928b3..2e00a23de7c 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -16,11 +16,13 @@ import { IssuableType } from '~/issue_show/constants'; import { __, s__, sprintf } from '~/locale'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; import { + Tracking, IssuableAttributeState, IssuableAttributeType, issuableAttributesQueries, noAttributeId, -} from '../constants'; + defaultEpicSort, +} from '~/sidebar/constants'; export default { noAttributeId, @@ -28,6 +30,7 @@ export default { issuableAttributesQueries, i18n: { [IssuableAttributeType.Milestone]: __('Milestone'), + expired: __('(expired)'), none: __('None'), }, directives: { @@ -73,9 +76,14 @@ export default { type: String, required: true, validator(value) { - return value === IssuableType.Issue; + return [IssuableType.Issue, IssuableType.MergeRequest].includes(value); }, }, + icon: { + type: String, + required: false, + default: undefined, + }, }, apollo: { currentAttribute: { @@ -117,7 +125,9 @@ export default { return { fullPath: this.attrWorkspacePath, title: this.searchTerm, + in: this.searchTerm && this.issuableAttribute === IssuableType.Epic ? 'TITLE' : undefined, state: this.$options.IssuableAttributeState[this.issuableAttribute], + sort: this.issuableAttribute === IssuableType.Epic ? defaultEpicSort : null, }; }, update(data) { @@ -140,8 +150,8 @@ export default { currentAttribute: null, attributesList: [], tracking: { - label: 'right_sidebar', - event: 'click_edit_button', + event: Tracking.editEvent, + label: Tracking.rightSidebarLabel, property: this.issuableAttribute, }, }; @@ -170,6 +180,9 @@ export default { attributeTypeTitle() { return this.$options.i18n[this.issuableAttribute]; }, + attributeTypeIcon() { + return this.icon || this.issuableAttribute; + }, i18n() { return { noAttribute: sprintf(s__('DropdownWidget|No %{issuableAttribute}'), { @@ -222,7 +235,8 @@ export default { variables: { fullPath: this.workspacePath, attributeId: - this.issuableAttribute === IssuableAttributeType.Milestone + this.issuableAttribute === IssuableAttributeType.Milestone && + this.issuableType === IssuableType.Issue ? getIdFromGraphQLId(attributeId) : attributeId, iid: this.iid, @@ -253,6 +267,11 @@ export default { attributeId === this.currentAttribute?.id || (!this.currentAttribute?.id && !attributeId) ); }, + isAttributeOverdue(attribute) { + return this.issuableAttribute === IssuableAttributeType.Milestone + ? attribute?.expired + : false; + }, showDropdown() { this.$refs.newDropdown.show(); }, @@ -282,8 +301,10 @@ export default { > <template #collapsed> <div v-if="isClassicSidebar" v-gl-tooltip class="sidebar-collapsed-icon"> - <gl-icon :size="16" :aria-label="attributeTypeTitle" :name="issuableAttribute" /> - <span class="collapse-truncated-title">{{ attributeTitle }}</span> + <gl-icon :size="16" :aria-label="attributeTypeTitle" :name="attributeTypeIcon" /> + <span class="collapse-truncated-title"> + {{ attributeTitle }} + </span> </div> <div :data-testid="`select-${issuableAttribute}`" @@ -300,8 +321,13 @@ export default { :attributeUrl="attributeUrl" :currentAttribute="currentAttribute" > - <gl-link class="gl-text-gray-900! gl-font-weight-bold" :href="attributeUrl"> + <gl-link + class="gl-text-gray-900! gl-font-weight-bold" + :href="attributeUrl" + :data-qa-selector="`${issuableAttribute}_link`" + > {{ attributeTitle }} + <span v-if="isAttributeOverdue(currentAttribute)">{{ $options.i18n.expired }}</span> </gl-link> </slot> </div> @@ -328,6 +354,7 @@ export default { <gl-dropdown-divider /> <gl-loading-icon v-if="$apollo.queries.attributesList.loading" + size="sm" class="gl-py-4" data-testid="loading-icon-dropdown" /> @@ -351,6 +378,7 @@ export default { @click="updateAttribute(attrItem.id)" > {{ attrItem.title }} + <span v-if="isAttributeOverdue(attrItem)">{{ $options.i18n.expired }}</span> </gl-dropdown-item> </slot> </template> diff --git a/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue b/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue index 825d7ff5841..7c496cc422a 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue @@ -117,9 +117,15 @@ export default { {{ title }} </span> <slot name="title-extra"></slot> - <gl-loading-icon v-if="loading || initialLoading" inline class="gl-ml-2 hide-collapsed" /> + <gl-loading-icon + v-if="loading || initialLoading" + size="sm" + inline + class="gl-ml-2 hide-collapsed" + /> <gl-loading-icon v-if="loading && isClassicSidebar" + size="sm" inline class="gl-mx-auto gl-my-0 hide-expanded" /> diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue index e97742a1339..bc7e377a966 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue @@ -2,17 +2,18 @@ import { GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui'; import createFlash from '~/flash'; import { IssuableType } from '~/issue_show/constants'; +import { isLoggedIn } from '~/lib/utils/common_utils'; import { __, sprintf } from '~/locale'; import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; -import { subscribedQueries } from '~/sidebar/constants'; +import { subscribedQueries, Tracking } from '~/sidebar/constants'; const ICON_ON = 'notifications'; const ICON_OFF = 'notifications-off'; export default { tracking: { - event: 'click_edit_button', - label: 'right_sidebar', + event: Tracking.editEvent, + label: Tracking.rightSidebarLabel, property: 'subscriptions', }, directives: { @@ -102,7 +103,7 @@ export default { }); }, isLoggedIn() { - return Boolean(gon.current_user_id); + return isLoggedIn(); }, canSubscribe() { return this.emailsDisabled || !this.isLoggedIn; @@ -195,7 +196,7 @@ export default { class="sidebar-collapsed-icon" @click="toggleSubscribed" > - <gl-loading-icon v-if="isLoading" class="sidebar-item-icon is-active" /> + <gl-loading-icon v-if="isLoading" size="sm" class="sidebar-item-icon is-active" /> <gl-icon v-else :name="notificationIcon" :size="16" class="sidebar-item-icon is-active" /> </span> <div v-show="emailsDisabled" class="gl-mt-3 hide-collapsed gl-text-gray-500"> diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue index f91a78b7f1d..8a14998910b 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue @@ -1,6 +1,7 @@ <script> import { GlLoadingIcon, GlTable } from '@gitlab/ui'; import createFlash from '~/flash'; +import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { formatDate, parseSeconds, stringifyTime } from '~/lib/utils/datetime_utility'; import { __ } from '~/locale'; @@ -52,8 +53,7 @@ export default { return this.issuableType === 'issue'; }, getGraphQLEntityType() { - // eslint-disable-next-line @gitlab/require-i18n-strings - return this.isIssue() ? 'Issue' : 'MergeRequest'; + return this.isIssue() ? TYPE_ISSUE : TYPE_MERGE_REQUEST; }, extractTimelogs(data) { const timelogs = data?.issuable?.timelogs?.nodes || []; diff --git a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue index 87ddbbf256a..9a9d03353dc 100644 --- a/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue +++ b/app/assets/javascripts/sidebar/components/time_tracking/time_tracker.vue @@ -200,7 +200,7 @@ export default { /> <div class="hide-collapsed gl-line-height-20 gl-text-gray-900"> {{ __('Time tracking') }} - <gl-loading-icon v-if="isTimeTrackingInfoLoading" inline /> + <gl-loading-icon v-if="isTimeTrackingInfoLoading" size="sm" inline /> <div v-if="!showHelpState" data-testid="helpButton" diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue new file mode 100644 index 00000000000..a9c4203af22 --- /dev/null +++ b/app/assets/javascripts/sidebar/components/todo_toggle/sidebar_todo_widget.vue @@ -0,0 +1,195 @@ +<script> +import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui'; +import { produce } from 'immer'; +import createFlash from '~/flash'; +import { __, sprintf } from '~/locale'; +import { todoQueries, TodoMutationTypes, todoMutations } from '~/sidebar/constants'; +import { todoLabel } from '~/vue_shared/components/sidebar/todo_toggle//utils'; +import TodoButton from '~/vue_shared/components/sidebar/todo_toggle/todo_button.vue'; + +export default { + components: { + GlButton, + GlIcon, + TodoButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + inject: { + isClassicSidebar: { + default: false, + }, + }, + props: { + issuableId: { + type: String, + required: true, + }, + issuableIid: { + type: String, + required: true, + }, + fullPath: { + type: String, + required: true, + }, + issuableType: { + required: true, + type: String, + }, + }, + data() { + return { + loading: false, + }; + }, + apollo: { + todoId: { + query() { + return todoQueries[this.issuableType].query; + }, + variables() { + return { + fullPath: this.fullPath, + iid: String(this.issuableIid), + }; + }, + update(data) { + return data.workspace?.issuable?.currentUserTodos.nodes[0]?.id; + }, + result({ data }) { + const currentUserTodos = data.workspace?.issuable?.currentUserTodos?.nodes ?? []; + this.todoId = currentUserTodos[0]?.id; + this.$emit('todoUpdated', currentUserTodos.length > 0); + }, + error() { + createFlash({ + message: sprintf(__('Something went wrong while setting %{issuableType} to-do item.'), { + issuableType: this.issuableType, + }), + }); + }, + }, + }, + computed: { + todoIdQuery() { + return todoQueries[this.issuableType].query; + }, + todoIdQueryVariables() { + return { + fullPath: this.fullPath, + iid: String(this.issuableIid), + }; + }, + isLoading() { + return this.$apollo.queries?.todoId?.loading || this.loading; + }, + hasTodo() { + return Boolean(this.todoId); + }, + todoMutationType() { + if (this.hasTodo) { + return TodoMutationTypes.MarkDone; + } + return TodoMutationTypes.Create; + }, + collapsedButtonIcon() { + return this.hasTodo ? 'todo-done' : 'todo-add'; + }, + tootltipTitle() { + return todoLabel(this.hasTodo); + }, + }, + methods: { + toggleTodo() { + this.loading = true; + this.$apollo + .mutate({ + mutation: todoMutations[this.todoMutationType], + variables: { + input: { + targetId: !this.hasTodo ? this.issuableId : undefined, + id: this.hasTodo ? this.todoId : undefined, + }, + }, + update: ( + store, + { + data: { + todoMutation: { todo }, + }, + }, + ) => { + const queryProps = { + query: this.todoIdQuery, + variables: this.todoIdQueryVariables, + }; + + const sourceData = store.readQuery(queryProps); + const data = produce(sourceData, (draftState) => { + draftState.workspace.issuable.currentUserTodos.nodes = this.hasTodo ? [] : [todo]; + }); + store.writeQuery({ + data, + ...queryProps, + }); + }, + }) + .then( + ({ + data: { + todoMutation: { errors }, + }, + }) => { + if (errors.length) { + createFlash({ + message: errors[0], + }); + } + }, + ) + .catch(() => { + createFlash({ + message: sprintf(__('Something went wrong while setting %{issuableType} to-do item.'), { + issuableType: this.issuableType, + }), + }); + }) + .finally(() => { + this.loading = false; + }); + }, + }, +}; +</script> + +<template> + <div data-testid="sidebar-todo"> + <todo-button + :issuable-type="issuableType" + :issuable-id="issuableId" + :is-todo="hasTodo" + :loading="isLoading" + size="small" + class="hide-collapsed" + @click.stop.prevent="toggleTodo" + /> + <gl-button + v-if="isClassicSidebar" + category="tertiary" + type="reset" + class="sidebar-collapsed-icon sidebar-collapsed-container gl-rounded-0! gl-shadow-none!" + @click.stop.prevent="toggleTodo" + > + <gl-icon + v-gl-tooltip.left.viewport + :title="tootltipTitle" + :size="16" + :class="{ 'todo-undone': hasTodo }" + :name="collapsedButtonIcon" + :aria-label="collapsedButtonIcon" + /> + </gl-button> + </div> +</template> diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue index f589e7555b3..f7e76cc2b7f 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue @@ -85,6 +85,6 @@ export default { :name="collapsedButtonIcon" /> <span v-show="!collapsed" class="issuable-todo-inner">{{ buttonLabel }}</span> - <gl-loading-icon v-show="isActionActive" :inline="true" /> + <gl-loading-icon v-show="isActionActive" size="sm" :inline="true" /> </button> </template> diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js index e8e69c19d9f..08ee4379c0c 100644 --- a/app/assets/javascripts/sidebar/constants.js +++ b/app/assets/javascripts/sidebar/constants.js @@ -1,18 +1,26 @@ import { IssuableType } from '~/issue_show/constants'; +import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import epicConfidentialQuery from '~/sidebar/queries/epic_confidential.query.graphql'; import epicDueDateQuery from '~/sidebar/queries/epic_due_date.query.graphql'; import epicParticipantsQuery from '~/sidebar/queries/epic_participants.query.graphql'; +import epicReferenceQuery from '~/sidebar/queries/epic_reference.query.graphql'; import epicStartDateQuery from '~/sidebar/queries/epic_start_date.query.graphql'; import epicSubscribedQuery from '~/sidebar/queries/epic_subscribed.query.graphql'; +import epicTodoQuery from '~/sidebar/queries/epic_todo.query.graphql'; import issuableAssigneesSubscription from '~/sidebar/queries/issuable_assignees.subscription.graphql'; import issueConfidentialQuery from '~/sidebar/queries/issue_confidential.query.graphql'; import issueDueDateQuery from '~/sidebar/queries/issue_due_date.query.graphql'; import issueReferenceQuery from '~/sidebar/queries/issue_reference.query.graphql'; import issueSubscribedQuery from '~/sidebar/queries/issue_subscribed.query.graphql'; import issueTimeTrackingQuery from '~/sidebar/queries/issue_time_tracking.query.graphql'; +import issueTodoQuery from '~/sidebar/queries/issue_todo.query.graphql'; +import mergeRequestMilestone from '~/sidebar/queries/merge_request_milestone.query.graphql'; import mergeRequestReferenceQuery from '~/sidebar/queries/merge_request_reference.query.graphql'; import mergeRequestSubscribed from '~/sidebar/queries/merge_request_subscribed.query.graphql'; import mergeRequestTimeTrackingQuery from '~/sidebar/queries/merge_request_time_tracking.query.graphql'; +import mergeRequestTodoQuery from '~/sidebar/queries/merge_request_todo.query.graphql'; +import todoCreateMutation from '~/sidebar/queries/todo_create.mutation.graphql'; +import todoMarkDoneMutation from '~/sidebar/queries/todo_mark_done.mutation.graphql'; import updateEpicConfidentialMutation from '~/sidebar/queries/update_epic_confidential.mutation.graphql'; import updateEpicDueDateMutation from '~/sidebar/queries/update_epic_due_date.mutation.graphql'; import updateEpicStartDateMutation from '~/sidebar/queries/update_epic_start_date.mutation.graphql'; @@ -20,6 +28,7 @@ import updateEpicSubscriptionMutation from '~/sidebar/queries/update_epic_subscr import updateIssueConfidentialMutation from '~/sidebar/queries/update_issue_confidential.mutation.graphql'; import updateIssueDueDateMutation from '~/sidebar/queries/update_issue_due_date.mutation.graphql'; import updateIssueSubscriptionMutation from '~/sidebar/queries/update_issue_subscription.mutation.graphql'; +import mergeRequestMilestoneMutation from '~/sidebar/queries/update_merge_request_milestone.mutation.graphql'; import updateMergeRequestSubscriptionMutation from '~/sidebar/queries/update_merge_request_subscription.mutation.graphql'; import updateAlertAssigneesMutation from '~/vue_shared/alert_details/graphql/mutations/alert_set_assignees.mutation.graphql'; import getAlertAssignees from '~/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql'; @@ -35,7 +44,9 @@ import projectIssueMilestoneMutation from './queries/project_issue_milestone.mut import projectIssueMilestoneQuery from './queries/project_issue_milestone.query.graphql'; import projectMilestonesQuery from './queries/project_milestones.query.graphql'; -export const ASSIGNEES_DEBOUNCE_DELAY = 250; +export const ASSIGNEES_DEBOUNCE_DELAY = DEFAULT_DEBOUNCE_AND_THROTTLE_MS; + +export const defaultEpicSort = 'TITLE_ASC'; export const assigneesQueries = { [IssuableType.Issue]: { @@ -87,6 +98,9 @@ export const referenceQueries = { [IssuableType.MergeRequest]: { query: mergeRequestReferenceQuery, }, + [IssuableType.Epic]: { + query: epicReferenceQuery, + }, }; export const dateTypes = { @@ -122,6 +136,11 @@ export const subscribedQueries = { }, }; +export const Tracking = { + editEvent: 'click_edit_button', + rightSidebarLabel: 'right_sidebar', +}; + export const timeTrackingQueries = { [IssuableType.Issue]: { query: issueTimeTrackingQuery, @@ -165,12 +184,19 @@ export const issuableMilestoneQueries = { query: projectIssueMilestoneQuery, mutation: projectIssueMilestoneMutation, }, + [IssuableType.MergeRequest]: { + query: mergeRequestMilestone, + mutation: mergeRequestMilestoneMutation, + }, }; export const milestonesQueries = { [IssuableType.Issue]: { query: projectMilestonesQuery, }, + [IssuableType.MergeRequest]: { + query: projectMilestonesQuery, + }, }; export const IssuableAttributeType = { @@ -187,3 +213,25 @@ export const issuableAttributesQueries = { list: milestonesQueries, }, }; + +export const todoQueries = { + [IssuableType.Epic]: { + query: epicTodoQuery, + }, + [IssuableType.Issue]: { + query: issueTodoQuery, + }, + [IssuableType.MergeRequest]: { + query: mergeRequestTodoQuery, + }, +}; + +export const TodoMutationTypes = { + Create: 'create', + MarkDone: 'mark-done', +}; + +export const todoMutations = { + [TodoMutationTypes.Create]: todoCreateMutation, + [TodoMutationTypes.MarkDone]: todoMarkDoneMutation, +}; diff --git a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js index 21cd24b0842..5a3122e83d0 100644 --- a/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js +++ b/app/assets/javascripts/sidebar/lib/sidebar_move_issue.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import { escape } from 'lodash'; import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown'; +import createFlash from '~/flash'; import { __ } from '~/locale'; function isValidProjectId(id) { @@ -42,8 +43,10 @@ class SidebarMoveIssue { this.mediator .fetchAutocompleteProjects(searchTerm) .then(callback) - .catch( - () => new window.Flash(__('An error occurred while fetching projects autocomplete.')), + .catch(() => + createFlash({ + message: __('An error occurred while fetching projects autocomplete.'), + }), ); }, renderRow: (project) => ` @@ -76,7 +79,7 @@ class SidebarMoveIssue { this.$confirmButton.disable().addClass('is-loading'); this.mediator.moveIssue().catch(() => { - window.Flash(__('An error occurred while moving the issue.')); + createFlash({ message: __('An error occurred while moving the issue.') }); this.$confirmButton.enable().removeClass('is-loading'); }); } diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 67c72b17f1f..dd1b439c482 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -2,6 +2,8 @@ import $ from 'jquery'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import createFlash from '~/flash'; +import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger'; import { IssuableType } from '~/issue_show/constants'; @@ -18,6 +20,8 @@ import SidebarConfidentialityWidget from '~/sidebar/components/confidential/side import SidebarDueDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue'; import SidebarParticipantsWidget from '~/sidebar/components/participants/sidebar_participants_widget.vue'; import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue'; +import SidebarDropdownWidget from '~/sidebar/components/sidebar_dropdown_widget.vue'; +import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue'; import { apolloProvider } from '~/sidebar/graphql'; import trackShowInviteMemberLink from '~/sidebar/track_invite_members'; import Translate from '../vue_shared/translate'; @@ -29,6 +33,7 @@ import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue'; import SidebarSeverity from './components/severity/sidebar_severity.vue'; import SidebarSubscriptionsWidget from './components/subscriptions/sidebar_subscriptions_widget.vue'; import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue'; +import { IssuableAttributeType } from './constants'; import SidebarMoveIssue from './lib/sidebar_move_issue'; Vue.use(Translate); @@ -38,6 +43,40 @@ function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-op return JSON.parse(sidebarOptEl.innerHTML); } +function mountSidebarToDoWidget() { + const el = document.querySelector('.js-issuable-todo'); + + if (!el) { + return false; + } + + const { projectPath, iid, id } = el.dataset; + + return new Vue({ + el, + apolloProvider, + components: { + SidebarTodoWidget, + }, + provide: { + isClassicSidebar: true, + }, + render: (createElement) => + createElement('sidebar-todo-widget', { + props: { + fullPath: projectPath, + issuableId: + isInIssuePage() || isInDesignPage() + ? convertToGraphQLId(TYPE_ISSUE, id) + : convertToGraphQLId(TYPE_MERGE_REQUEST, id), + issuableIid: iid, + issuableType: + isInIssuePage() || isInDesignPage() ? IssuableType.Issue : IssuableType.MergeRequest, + }, + }), + }); +} + function getSidebarAssigneeAvailabilityData() { const sidebarAssigneeEl = document.querySelectorAll('.js-sidebar-assignee-data input'); return Array.from(sidebarAssigneeEl) @@ -154,7 +193,8 @@ function mountReviewersComponent(mediator) { issuableIid: String(iid), projectPath: fullPath, field: el.dataset.field, - issuableType: isInIssuePage() || isInDesignPage() ? 'issue' : 'merge_request', + issuableType: + isInIssuePage() || isInDesignPage() ? IssuableType.Issue : IssuableType.MergeRequest, }, }), }); @@ -166,6 +206,40 @@ function mountReviewersComponent(mediator) { } } +function mountMilestoneSelect() { + const el = document.querySelector('.js-milestone-select'); + + if (!el) { + return false; + } + + const { canEdit, projectPath, issueIid } = el.dataset; + + return new Vue({ + el, + apolloProvider, + components: { + SidebarDropdownWidget, + }, + provide: { + canUpdate: parseBoolean(canEdit), + isClassicSidebar: true, + }, + render: (createElement) => + createElement('sidebar-dropdown-widget', { + props: { + attrWorkspacePath: projectPath, + workspacePath: projectPath, + iid: issueIid, + issuableType: + isInIssuePage() || isInDesignPage() ? IssuableType.Issue : IssuableType.MergeRequest, + issuableAttribute: IssuableAttributeType.Milestone, + icon: 'clock', + }, + }), + }); +} + export function mountSidebarLabels() { const el = document.querySelector('.js-sidebar-labels'); @@ -460,12 +534,14 @@ export function mountSidebar(mediator) { initInviteMembersModal(); initInviteMembersTrigger(); + mountSidebarToDoWidget(); if (isAssigneesWidgetShown) { mountAssigneesComponent(); } else { mountAssigneesComponentDeprecated(mediator); } mountReviewersComponent(mediator); + mountMilestoneSelect(); mountConfidentialComponent(mediator); mountDueDateComponent(mediator); mountReferenceComponent(mediator); diff --git a/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql b/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql new file mode 100644 index 00000000000..bd10f09aed8 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/epic_reference.query.graphql @@ -0,0 +1,10 @@ +query epicReference($fullPath: ID!, $iid: ID) { + workspace: group(fullPath: $fullPath) { + __typename + issuable: epic(iid: $iid) { + __typename + id + reference(full: true) + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql b/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql new file mode 100644 index 00000000000..1e6f9bad5b2 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/epic_todo.query.graphql @@ -0,0 +1,14 @@ +query epicTodos($fullPath: ID!, $iid: ID) { + workspace: group(fullPath: $fullPath) { + __typename + issuable: epic(iid: $iid) { + __typename + id + currentUserTodos(state: pending) { + nodes { + id + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql b/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql new file mode 100644 index 00000000000..783d36352fe --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/issue_todo.query.graphql @@ -0,0 +1,14 @@ +query issueTodos($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + __typename + issuable: issue(iid: $iid) { + __typename + id + currentUserTodos(state: pending) { + nodes { + id + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql new file mode 100644 index 00000000000..5c0edf5acee --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/merge_request_milestone.query.graphql @@ -0,0 +1,14 @@ +#import "./milestone.fragment.graphql" + +query mergeRequestMilestone($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + __typename + issuable: mergeRequest(iid: $iid) { + __typename + id + attribute: milestone { + ...MilestoneFragment + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql b/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql new file mode 100644 index 00000000000..93a1c9ea925 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/merge_request_todo.query.graphql @@ -0,0 +1,14 @@ +query mergeRequestTodos($fullPath: ID!, $iid: String!) { + workspace: project(fullPath: $fullPath) { + __typename + issuable: mergeRequest(iid: $iid) { + __typename + id + currentUserTodos(state: pending) { + nodes { + id + } + } + } + } +} diff --git a/app/assets/javascripts/sidebar/queries/milestone.fragment.graphql b/app/assets/javascripts/sidebar/queries/milestone.fragment.graphql index 8db5359dac0..2ffd58a2da1 100644 --- a/app/assets/javascripts/sidebar/queries/milestone.fragment.graphql +++ b/app/assets/javascripts/sidebar/queries/milestone.fragment.graphql @@ -2,4 +2,5 @@ fragment MilestoneFragment on Milestone { id title webUrl: webPath + expired } diff --git a/app/assets/javascripts/sidebar/queries/project_issue_milestone.mutation.graphql b/app/assets/javascripts/sidebar/queries/project_issue_milestone.mutation.graphql index d88ad8b1087..721a71bef63 100644 --- a/app/assets/javascripts/sidebar/queries/project_issue_milestone.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/project_issue_milestone.mutation.graphql @@ -11,6 +11,7 @@ mutation projectIssueMilestoneMutation($fullPath: ID!, $iid: String!, $attribute title id state + expired } } } diff --git a/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql b/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql index 1237640c468..a3ab1ebc872 100644 --- a/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql +++ b/app/assets/javascripts/sidebar/queries/project_milestones.query.graphql @@ -3,7 +3,13 @@ query projectMilestones($fullPath: ID!, $title: String, $state: MilestoneStateEnum) { workspace: project(fullPath: $fullPath) { __typename - attributes: milestones(searchTitle: $title, state: $state) { + attributes: milestones( + searchTitle: $title + state: $state + sort: EXPIRED_LAST_DUE_DATE_ASC + first: 20 + includeAncestors: true + ) { nodes { ...MilestoneFragment state diff --git a/app/assets/javascripts/sidebar/queries/todo_create.mutation.graphql b/app/assets/javascripts/sidebar/queries/todo_create.mutation.graphql new file mode 100644 index 00000000000..4675db9153e --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/todo_create.mutation.graphql @@ -0,0 +1,9 @@ +mutation issuableTodoCreate($input: TodoCreateInput!) { + todoMutation: todoCreate(input: $input) { + __typename + todo { + id + } + errors + } +} diff --git a/app/assets/javascripts/sidebar/queries/todo_mark_done.mutation.graphql b/app/assets/javascripts/sidebar/queries/todo_mark_done.mutation.graphql new file mode 100644 index 00000000000..8253e5e82bc --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/todo_mark_done.mutation.graphql @@ -0,0 +1,9 @@ +mutation issuableTodoMarkDone($input: TodoMarkDoneInput!) { + todoMutation: todoMarkDone(input: $input) { + __typename + todo { + id + } + errors + } +} diff --git a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql index b45b6b46c8f..28a47735143 100644 --- a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql +++ b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql @@ -1,6 +1,7 @@ mutation($projectPath: ID!, $iid: String!, $healthStatus: HealthStatus) { updateIssue(input: { projectPath: $projectPath, iid: $iid, healthStatus: $healthStatus }) { - issue { + issuable: issue { + id healthStatus } errors diff --git a/app/assets/javascripts/sidebar/queries/update_merge_request_milestone.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_merge_request_milestone.mutation.graphql new file mode 100644 index 00000000000..368f06fac7f --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/update_merge_request_milestone.mutation.graphql @@ -0,0 +1,17 @@ +mutation mergeRequestSetMilestone($fullPath: ID!, $iid: String!, $attributeId: ID) { + issuableSetAttribute: mergeRequestSetMilestone( + input: { projectPath: $fullPath, iid: $iid, milestoneId: $attributeId } + ) { + __typename + errors + issuable: mergeRequest { + __typename + id + attribute: milestone { + title + id + state + } + } + } +} diff --git a/app/assets/javascripts/sidebar/services/sidebar_service.js b/app/assets/javascripts/sidebar/services/sidebar_service.js index 88501f2c305..ace2a163adc 100644 --- a/app/assets/javascripts/sidebar/services/sidebar_service.js +++ b/app/assets/javascripts/sidebar/services/sidebar_service.js @@ -1,4 +1,5 @@ import sidebarDetailsIssueQuery from 'ee_else_ce/sidebar/queries/sidebarDetails.query.graphql'; +import { TYPE_USER } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import createGqClient, { fetchPolicies } from '~/lib/graphql'; import axios from '~/lib/utils/axios_utils'; @@ -88,7 +89,7 @@ export default class SidebarService { return gqClient.mutate({ mutation: reviewerRereviewMutation, variables: { - userId: convertToGraphQLId('User', `${userId}`), // eslint-disable-line @gitlab/require-i18n-strings + userId: convertToGraphQLId(TYPE_USER, `${userId}`), projectPath: this.fullPath, iid: this.iid.toString(), }, diff --git a/app/assets/javascripts/sidebar/sidebar_mediator.js b/app/assets/javascripts/sidebar/sidebar_mediator.js index 3595354da80..0a5e44a9b95 100644 --- a/app/assets/javascripts/sidebar/sidebar_mediator.js +++ b/app/assets/javascripts/sidebar/sidebar_mediator.js @@ -1,7 +1,7 @@ import Store from 'ee_else_ce/sidebar/stores/sidebar_store'; +import createFlash from '~/flash'; import { __ } from '~/locale'; import toast from '~/vue_shared/plugins/global_toast'; -import { deprecatedCreateFlash as Flash } from '../flash'; import { visitUrl } from '../lib/utils/url_utility'; import Service from './services/sidebar_service'; @@ -74,7 +74,11 @@ export default class SidebarMediator { .then(([restResponse, graphQlResponse]) => { this.processFetchedData(restResponse.data, graphQlResponse.data); }) - .catch(() => new Flash(__('Error occurred when fetching sidebar data'))); + .catch(() => + createFlash({ + message: __('Error occurred when fetching sidebar data'), + }), + ); } processFetchedData(data) { |