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>2021-11-18 16:16:36 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-11-18 16:16:36 +0300
commit311b0269b4eb9839fa63f80c8d7a58f32b8138a0 (patch)
tree07e7870bca8aed6d61fdcc810731c50d2c40af47 /app/assets/javascripts/sidebar
parent27909cef6c4170ed9205afa7426b8d3de47cbb0c (diff)
Add latest changes from gitlab-org/gitlab@14-5-stable-eev14.5.0-rc42
Diffstat (limited to 'app/assets/javascripts/sidebar')
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/assignees.vue10
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue6
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue50
-rw-r--r--app/assets/javascripts/sidebar/components/attention_requested_toggle.vue74
-rw-r--r--app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue9
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/reviewers.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue4
-rw-r--r--app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue17
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue1
-rw-r--r--app/assets/javascripts/sidebar/components/sidebar_editable_item.vue2
-rw-r--r--app/assets/javascripts/sidebar/components/time_tracking/report.vue8
-rw-r--r--app/assets/javascripts/sidebar/constants.js28
-rw-r--r--app/assets/javascripts/sidebar/graphql.js1
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js4
-rw-r--r--app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/toggle_attention_requested.mutation.graphql7
-rw-r--r--app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_confidential.mutation.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_subscription.mutation.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_issue_subscription.mutation.graphql2
-rw-r--r--app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql1
-rw-r--r--app/assets/javascripts/sidebar/services/sidebar_service.js12
-rw-r--r--app/assets/javascripts/sidebar/sidebar_mediator.js43
-rw-r--r--app/assets/javascripts/sidebar/stores/sidebar_store.js12
26 files changed, 280 insertions, 29 deletions
diff --git a/app/assets/javascripts/sidebar/components/assignees/assignees.vue b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
index e41bb41dc05..bdd014163a0 100644
--- a/app/assets/javascripts/sidebar/components/assignees/assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/assignees.vue
@@ -39,6 +39,9 @@ export default {
assignSelf() {
this.$emit('assign-self');
},
+ toggleAttentionRequested(data) {
+ this.$emit('toggle-attention-requested', data);
+ },
},
};
</script>
@@ -58,7 +61,12 @@ export default {
</template>
</span>
- <uncollapsed-assignee-list v-else :users="sortedAssigness" :issuable-type="issuableType" />
+ <uncollapsed-assignee-list
+ v-else
+ :users="sortedAssigness"
+ :issuable-type="issuableType"
+ @toggle-attention-requested="toggleAttentionRequested"
+ />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue
index 80caebad39d..a3379784bc1 100644
--- a/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/issuable_assignees.vue
@@ -32,6 +32,11 @@ export default {
return this.users.length === 0;
},
},
+ methods: {
+ toggleAttentionRequested(data) {
+ this.$emit('toggle-attention-requested', data);
+ },
+ },
};
</script>
@@ -61,6 +66,7 @@ export default {
:users="users"
:issuable-type="issuableType"
class="gl-text-gray-800 gl-mt-2 hide-collapsed"
+ @toggle-attention-requested="toggleAttentionRequested"
/>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
index c6877226b7d..453dd1b0580 100644
--- a/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/sidebar_assignees.vue
@@ -125,6 +125,9 @@ export default {
availability: this.assigneeAvailabilityStatus[username] || '',
}));
},
+ toggleAttentionRequested(data) {
+ this.mediator.toggleAttentionRequested('assignee', data);
+ },
},
};
</script>
@@ -152,6 +155,7 @@ export default {
:editable="store.editable"
:issuable-type="issuableType"
@assign-self="assignSelf"
+ @toggle-attention-requested="toggleAttentionRequested"
/>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
index c2ca87af9ce..8d5c3b2def3 100644
--- a/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
+++ b/app/assets/javascripts/sidebar/components/assignees/uncollapsed_assignee_list.vue
@@ -1,6 +1,8 @@
<script>
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { IssuableType } from '~/issue_show/constants';
import { __, sprintf } from '~/locale';
+import AttentionRequestedToggle from '../attention_requested_toggle.vue';
import AssigneeAvatarLink from './assignee_avatar_link.vue';
import UserNameWithStatus from './user_name_with_status.vue';
@@ -8,9 +10,11 @@ const DEFAULT_RENDER_COUNT = 5;
export default {
components: {
+ AttentionRequestedToggle,
AssigneeAvatarLink,
UserNameWithStatus,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
users: {
type: Array,
@@ -32,6 +36,10 @@ export default {
return this.users[0];
},
hasOneUser() {
+ if (this.showVerticalList) {
+ return false;
+ }
+
return this.users.length === 1;
},
hiddenAssigneesLabel() {
@@ -45,6 +53,10 @@ export default {
return this.users.length - DEFAULT_RENDER_COUNT;
},
uncollapsedUsers() {
+ if (this.showVerticalList) {
+ return this.users;
+ }
+
const uncollapsedLength = this.showLess
? Math.min(this.users.length, DEFAULT_RENDER_COUNT)
: this.users.length;
@@ -53,6 +65,12 @@ export default {
username() {
return `@${this.firstUser.username}`;
},
+ showVerticalList() {
+ return this.glFeatures.mrAttentionRequests && this.isMergeRequest;
+ },
+ isMergeRequest() {
+ return this.issuableType === IssuableType.MergeRequest;
+ },
},
methods: {
toggleShowLess() {
@@ -64,6 +82,9 @@ export default {
}
return u?.status?.availability || '';
},
+ toggleAttentionRequested(data) {
+ this.$emit('toggle-attention-requested', data);
+ },
},
};
</script>
@@ -84,11 +105,34 @@ export default {
<div v-else>
<div class="gl-display-flex gl-flex-wrap">
<div
- v-for="user in uncollapsedUsers"
+ v-for="(user, index) in uncollapsedUsers"
:key="user.id"
- class="user-item gl-display-inline-block"
+ :class="{
+ 'user-item': !showVerticalList,
+ 'gl-mb-3': index !== users.length - 1 && showVerticalList,
+ }"
+ class="gl-display-inline-block"
>
- <assignee-avatar-link :user="user" :issuable-type="issuableType" />
+ <attention-requested-toggle
+ v-if="showVerticalList && user.can_update_merge_request"
+ :user="user"
+ type="assignee"
+ @toggle-attention-requested="toggleAttentionRequested"
+ />
+ <assignee-avatar-link
+ :user="user"
+ :issuable-type="issuableType"
+ :tooltip-has-name="!showVerticalList"
+ >
+ <div
+ v-if="showVerticalList"
+ class="gl-ml-3 gl-line-height-normal gl-display-grid"
+ data-testid="username"
+ >
+ <user-name-with-status :name="user.name" :availability="userAvailability(user)" />
+ <span>@{{ user.username }}</span>
+ </div>
+ </assignee-avatar-link>
</div>
</div>
<div v-if="renderShowMoreSection" class="user-list-more gl-hover-text-blue-800">
diff --git a/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue
new file mode 100644
index 00000000000..38ba468d197
--- /dev/null
+++ b/app/assets/javascripts/sidebar/components/attention_requested_toggle.vue
@@ -0,0 +1,74 @@
+<script>
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
+import { __ } from '~/locale';
+import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
+
+export default {
+ i18n: {
+ attentionRequestedReviewer: __('Request attention to review'),
+ attentionRequestedAssignee: __('Request attention'),
+ removeAttentionRequested: __('Remove attention request'),
+ },
+ components: {
+ GlButton,
+ },
+ directives: {
+ GlTooltip: GlTooltipDirective,
+ },
+ props: {
+ type: {
+ type: String,
+ required: true,
+ },
+ user: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ loading: false,
+ };
+ },
+ computed: {
+ tooltipTitle() {
+ if (this.user.attention_requested) {
+ return this.$options.i18n.removeAttentionRequested;
+ }
+
+ return this.type === 'reviewer'
+ ? this.$options.i18n.attentionRequestedReviewer
+ : this.$options.i18n.attentionRequestedAssignee;
+ },
+ },
+ methods: {
+ toggleAttentionRequired() {
+ if (this.loading) return;
+
+ this.$root.$emit(BV_HIDE_TOOLTIP);
+ this.loading = true;
+ this.$emit('toggle-attention-requested', {
+ user: this.user,
+ callback: this.toggleAttentionRequiredComplete,
+ });
+ },
+ toggleAttentionRequiredComplete() {
+ this.loading = false;
+ },
+ },
+};
+</script>
+
+<template>
+ <span v-gl-tooltip.left.viewport="tooltipTitle">
+ <gl-button
+ :loading="loading"
+ :variant="user.attention_requested ? 'warning' : 'default'"
+ :icon="user.attention_requested ? 'star' : 'star-o'"
+ :aria-label="tooltipTitle"
+ size="small"
+ category="tertiary"
+ @click="toggleAttentionRequired"
+ />
+ </span>
+</template>
diff --git a/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
index d5647619ea3..5cd4a1a5192 100644
--- a/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
+++ b/app/assets/javascripts/sidebar/components/labels/sidebar_labels.vue
@@ -11,6 +11,7 @@ import { toLabelGid } from '~/sidebar/utils';
import { DropdownVariant } from '~/vue_shared/components/sidebar/labels_select_vue/constants';
import LabelsSelect from '~/vue_shared/components/sidebar/labels_select_vue/labels_select_root.vue';
import LabelsSelectWidget from '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue';
+import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const mutationMap = {
@@ -48,6 +49,7 @@ export default {
return {
isLabelsSelectInProgress: false,
selectedLabels: this.initiallySelectedLabels,
+ LabelType,
};
},
methods: {
@@ -154,13 +156,12 @@ export default {
:footer-manage-label-title="__('Manage project labels')"
:labels-create-title="__('Create project label')"
:labels-filter-base-path="projectIssuesPath"
- :labels-select-in-progress="isLabelsSelectInProgress"
- :selected-labels="selectedLabels"
:variant="$options.variant"
:issuable-type="issuableType"
+ workspace-type="project"
+ :attr-workspace-path="fullPath"
+ :label-create-type="LabelType.project"
data-qa-selector="labels_block"
- @onLabelRemove="handleLabelRemove"
- @updateSelectedLabels="handleUpdateSelectedLabels"
>
{{ __('None') }}
</labels-select-widget>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
index 5729b958b5d..b07fd944ff9 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/reviewers.vue
@@ -49,6 +49,9 @@ export default {
requestReview(data) {
this.$emit('request-review', data);
},
+ toggleAttentionRequested(data) {
+ this.$emit('toggle-attention-requested', data);
+ },
},
};
</script>
@@ -70,6 +73,7 @@ export default {
:root-path="rootPath"
:issuable-type="issuableType"
@request-review="requestReview"
+ @toggle-attention-requested="toggleAttentionRequested"
/>
</div>
</div>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
index e414aaf719b..2ea63219e92 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/sidebar_reviewers.vue
@@ -88,6 +88,9 @@ export default {
requestReview(data) {
this.mediator.requestReview(data);
},
+ toggleAttentionRequested(data) {
+ this.mediator.toggleAttentionRequested('reviewer', data);
+ },
},
};
</script>
@@ -106,6 +109,7 @@ export default {
:editable="store.editable"
:issuable-type="issuableType"
@request-review="requestReview"
+ @toggle-attention-requested="toggleAttentionRequested"
/>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
index 2922008cfb2..adaf1b65f3f 100644
--- a/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
+++ b/app/assets/javascripts/sidebar/components/reviewers/uncollapsed_reviewer_list.vue
@@ -1,6 +1,8 @@
<script>
import { GlButton, GlTooltipDirective, GlIcon } from '@gitlab/ui';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __, sprintf, s__ } from '~/locale';
+import AttentionRequestedToggle from '../attention_requested_toggle.vue';
import ReviewerAvatarLink from './reviewer_avatar_link.vue';
const LOADING_STATE = 'loading';
@@ -14,10 +16,12 @@ export default {
GlButton,
GlIcon,
ReviewerAvatarLink,
+ AttentionRequestedToggle,
},
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
users: {
type: Array,
@@ -76,6 +80,9 @@ export default {
this.loadingStates[userId] = null;
}
},
+ toggleAttentionRequested(data) {
+ this.$emit('toggle-attention-requested', data);
+ },
},
LOADING_STATE,
SUCCESS_STATE,
@@ -90,6 +97,12 @@ export default {
:class="{ 'gl-mb-3': index !== users.length - 1 }"
data-testid="reviewer"
>
+ <attention-requested-toggle
+ v-if="glFeatures.mrAttentionRequests && user.can_update_merge_request"
+ :user="user"
+ type="reviewer"
+ @toggle-attention-requested="toggleAttentionRequested"
+ />
<reviewer-avatar-link :user="user" :root-path="rootPath" :issuable-type="issuableType">
<div class="gl-ml-3 gl-line-height-normal gl-display-grid">
<span>{{ user.name }}</span>
@@ -113,7 +126,9 @@ export default {
data-testid="re-request-success"
/>
<gl-button
- v-else-if="user.can_update_merge_request && user.reviewed"
+ v-else-if="
+ user.can_update_merge_request && user.reviewed && !glFeatures.mrAttentionRequests
+ "
v-gl-tooltip.left
:title="$options.i18n.reRequestReview"
:aria-label="$options.i18n.reRequestReview"
diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
index 8f4d5406da8..0ba8c4f8907 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue
@@ -370,6 +370,7 @@ export default {
:loading="loading"
class="gl-w-full"
toggle-class="gl-max-w-100"
+ block
@shown="setFocus"
>
<gl-search-box-by-type ref="search" v-model="searchTerm" />
diff --git a/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue b/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue
index 22adbd79ef6..056b3e98a1c 100644
--- a/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue
+++ b/app/assets/javascripts/sidebar/components/sidebar_editable_item.vue
@@ -134,7 +134,7 @@ export default {
v-if="canUpdate && !initialLoading && canEdit"
category="tertiary"
size="small"
- class="gl-text-gray-900! gl-ml-auto hide-collapsed gl-mr-n2"
+ class="gl-text-gray-900! gl-ml-auto hide-collapsed gl-mr-n2 shortcut-sidebar-dropdown-toggle"
data-testid="edit-button"
:data-track-action="tracking.event"
:data-track-label="tracking.label"
diff --git a/app/assets/javascripts/sidebar/components/time_tracking/report.vue b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
index d4a8abb81a8..5d4031ac68b 100644
--- a/app/assets/javascripts/sidebar/components/time_tracking/report.vue
+++ b/app/assets/javascripts/sidebar/components/time_tracking/report.vue
@@ -1,5 +1,5 @@
<script>
-import { GlLoadingIcon, GlTable } from '@gitlab/ui';
+import { GlLoadingIcon, GlTableLite } from '@gitlab/ui';
import createFlash from '~/flash';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
@@ -12,7 +12,7 @@ const TIME_DATE_FORMAT = 'mmmm d, yyyy, HH:MM ("UTC:" o)';
export default {
components: {
GlLoadingIcon,
- GlTable,
+ GlTableLite,
},
inject: ['issuableType'],
props: {
@@ -89,7 +89,7 @@ export default {
<template>
<div>
<div v-if="isLoading"><gl-loading-icon size="md" /></div>
- <gl-table v-else :items="report" :fields="$options.fields" foot-clone>
+ <gl-table-lite v-else :items="report" :fields="$options.fields" foot-clone>
<template #cell(spentAt)="{ item: { spentAt } }">
<div>{{ formatDate(spentAt) }}</div>
</template>
@@ -111,6 +111,6 @@ export default {
<div>{{ getSummary(summary, note) }}</div>
</template>
<template #foot(note)>&nbsp;</template>
- </gl-table>
+ </gl-table-lite>
</div>
</template>
diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js
index e593973da82..ac34a75ac5c 100644
--- a/app/assets/javascripts/sidebar/constants.js
+++ b/app/assets/javascripts/sidebar/constants.js
@@ -1,4 +1,5 @@
-import { IssuableType } from '~/issue_show/constants';
+import updateIssueLabelsMutation from '~/boards/graphql/issue_set_labels.mutation.graphql';
+import { IssuableType, WorkspaceType } 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';
@@ -29,11 +30,14 @@ import updateIssueConfidentialMutation from '~/sidebar/queries/update_issue_conf
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 updateMergeRequestLabelsMutation from '~/sidebar/queries/update_merge_request_labels.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 epicLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_labels.query.graphql';
+import updateEpicLabelsMutation from '~/vue_shared/components/sidebar/labels_select_widget/graphql/epic_update_labels.mutation.graphql';
import groupLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/group_labels.query.graphql';
import issueLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/issue_labels.query.graphql';
+import mergeRequestLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/merge_request_labels.query.graphql';
import projectLabelsQuery from '~/vue_shared/components/sidebar/labels_select_widget/graphql/project_labels.query.graphql';
import getAlertAssignees from '~/vue_shared/components/sidebar/queries/get_alert_assignees.query.graphql';
import getIssueAssignees from '~/vue_shared/components/sidebar/queries/get_issue_assignees.query.graphql';
@@ -109,14 +113,30 @@ export const referenceQueries = {
},
};
-export const labelsQueries = {
+export const workspaceLabelsQueries = {
+ [WorkspaceType.project]: {
+ query: projectLabelsQuery,
+ },
+ [WorkspaceType.group]: {
+ query: groupLabelsQuery,
+ },
+};
+
+export const issuableLabelsQueries = {
[IssuableType.Issue]: {
issuableQuery: issueLabelsQuery,
- workspaceQuery: projectLabelsQuery,
+ mutation: updateIssueLabelsMutation,
+ mutationName: 'updateIssue',
+ },
+ [IssuableType.MergeRequest]: {
+ issuableQuery: mergeRequestLabelsQuery,
+ mutation: updateMergeRequestLabelsMutation,
+ mutationName: 'mergeRequestSetLabels',
},
[IssuableType.Epic]: {
issuableQuery: epicLabelsQuery,
- workspaceQuery: groupLabelsQuery,
+ mutation: updateEpicLabelsMutation,
+ mutationName: 'updateEpic',
},
};
diff --git a/app/assets/javascripts/sidebar/graphql.js b/app/assets/javascripts/sidebar/graphql.js
index 1a806a051b7..6a670db2d38 100644
--- a/app/assets/javascripts/sidebar/graphql.js
+++ b/app/assets/javascripts/sidebar/graphql.js
@@ -25,7 +25,6 @@ export const defaultClient = createDefaultClient(resolvers, {
cacheConfig: {
fragmentMatcher,
},
- assumeImmutableResults: true,
});
export const apolloProvider = new VueApollo({
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 9f5a2f4ebb0..898be4a97ce 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -260,6 +260,10 @@ export function mountSidebarLabels() {
variant: DropdownVariant.Sidebar,
canUpdate: parseBoolean(el.dataset.canEdit),
isClassicSidebar: true,
+ issuableType:
+ isInIssuePage() || isInIncidentPage() || isInDesignPage()
+ ? IssuableType.Issue
+ : IssuableType.MergeRequest,
},
render: (createElement) => createElement(SidebarLabels),
});
diff --git a/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql b/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql
index 2aff7da4605..dd85eb1631b 100644
--- a/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql
+++ b/app/assets/javascripts/sidebar/queries/sidebarDetails.query.graphql
@@ -1,4 +1,4 @@
-query($fullPath: ID!, $iid: String!) {
+query sidebarDetails($fullPath: ID!, $iid: String!) {
project(fullPath: $fullPath) {
issue(iid: $iid) {
iid
diff --git a/app/assets/javascripts/sidebar/queries/toggle_attention_requested.mutation.graphql b/app/assets/javascripts/sidebar/queries/toggle_attention_requested.mutation.graphql
new file mode 100644
index 00000000000..a9f4af6e1b9
--- /dev/null
+++ b/app/assets/javascripts/sidebar/queries/toggle_attention_requested.mutation.graphql
@@ -0,0 +1,7 @@
+mutation mergeRequestToggleAttentionRequested($projectPath: ID!, $iid: String!, $userId: ID!) {
+ mergeRequestToggleAttentionRequested(
+ input: { projectPath: $projectPath, iid: $iid, userId: $userId }
+ ) {
+ errors
+ }
+}
diff --git a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
index 28a47735143..2c6f379744e 100644
--- a/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/updateStatus.mutation.graphql
@@ -1,4 +1,4 @@
-mutation($projectPath: ID!, $iid: String!, $healthStatus: HealthStatus) {
+mutation updateIssueHealthStatus($projectPath: ID!, $iid: String!, $healthStatus: HealthStatus) {
updateIssue(input: { projectPath: $projectPath, iid: $iid, healthStatus: $healthStatus }) {
issuable: issue {
id
diff --git a/app/assets/javascripts/sidebar/queries/update_epic_confidential.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_confidential.mutation.graphql
index 69927ddd205..2d58843140f 100644
--- a/app/assets/javascripts/sidebar/queries/update_epic_confidential.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_epic_confidential.mutation.graphql
@@ -1,4 +1,4 @@
-mutation updateEpic($input: UpdateEpicInput!) {
+mutation updateIssuableConfidential($input: UpdateEpicInput!) {
issuableSetConfidential: updateEpic(input: $input) {
issuable: epic {
id
diff --git a/app/assets/javascripts/sidebar/queries/update_epic_subscription.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_subscription.mutation.graphql
index af43766aed5..4a3090f3836 100644
--- a/app/assets/javascripts/sidebar/queries/update_epic_subscription.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_epic_subscription.mutation.graphql
@@ -1,4 +1,4 @@
-mutation epicSetSubscription($fullPath: ID!, $iid: ID!, $subscribedState: Boolean!) {
+mutation boardEpicSetSubscription($fullPath: ID!, $iid: ID!, $subscribedState: Boolean!) {
updateIssuableSubscription: epicSetSubscription(
input: { groupPath: $fullPath, iid: $iid, subscribedState: $subscribedState }
) {
diff --git a/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql
index 317b48c142d..2e6bc8c36ba 100644
--- a/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_epic_title.mutation.graphql
@@ -1,4 +1,4 @@
-mutation updateEpic($input: UpdateEpicInput!) {
+mutation updateEpicTitle($input: UpdateEpicInput!) {
updateIssuableTitle: updateEpic(input: $input) {
epic {
title
diff --git a/app/assets/javascripts/sidebar/queries/update_issue_subscription.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_issue_subscription.mutation.graphql
index 81891fb601f..e1a3927e7e1 100644
--- a/app/assets/javascripts/sidebar/queries/update_issue_subscription.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_issue_subscription.mutation.graphql
@@ -1,4 +1,4 @@
-mutation issueSetSubscription($fullPath: ID!, $iid: String!, $subscribedState: Boolean!) {
+mutation projectIssueSetSubscription($fullPath: ID!, $iid: String!, $subscribedState: Boolean!) {
updateIssuableSubscription: issueSetSubscription(
input: { projectPath: $fullPath, iid: $iid, subscribedState: $subscribedState }
) {
diff --git a/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql b/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
index 3c09daad793..016c31ea096 100644
--- a/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
+++ b/app/assets/javascripts/sidebar/queries/update_merge_request_labels.mutation.graphql
@@ -2,6 +2,7 @@ mutation mergeRequestSetLabels($input: MergeRequestSetLabelsInput!) {
mergeRequestSetLabels(input: $input) {
errors
mergeRequest {
+ id
labels {
nodes {
color
diff --git a/app/assets/javascripts/sidebar/services/sidebar_service.js b/app/assets/javascripts/sidebar/services/sidebar_service.js
index cea26acd101..d8ab8f1c65b 100644
--- a/app/assets/javascripts/sidebar/services/sidebar_service.js
+++ b/app/assets/javascripts/sidebar/services/sidebar_service.js
@@ -5,6 +5,7 @@ import createGqClient, { fetchPolicies } from '~/lib/graphql';
import axios from '~/lib/utils/axios_utils';
import reviewerRereviewMutation from '../queries/reviewer_rereview.mutation.graphql';
import sidebarDetailsMRQuery from '../queries/sidebarDetailsMR.query.graphql';
+import toggleAttentionRequestedMutation from '../queries/toggle_attention_requested.mutation.graphql';
const queries = {
merge_request: sidebarDetailsMRQuery,
@@ -90,4 +91,15 @@ export default class SidebarService {
},
});
}
+
+ toggleAttentionRequested(userId) {
+ return gqClient.mutate({
+ mutation: toggleAttentionRequestedMutation,
+ variables: {
+ 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 9144e3b08db..86580744ccc 100644
--- a/app/assets/javascripts/sidebar/sidebar_mediator.js
+++ b/app/assets/javascripts/sidebar/sidebar_mediator.js
@@ -1,6 +1,6 @@
import Store from 'ee_else_ce/sidebar/stores/sidebar_store';
import createFlash from '~/flash';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import toast from '~/vue_shared/plugins/global_toast';
import { visitUrl } from '../lib/utils/url_utility';
import Service from './services/sidebar_service';
@@ -56,13 +56,52 @@ export default class SidebarMediator {
return this.service
.requestReview(userId)
.then(() => {
- this.store.updateReviewer(userId);
+ this.store.updateReviewer(userId, 'reviewed');
toast(__('Requested review'));
callback(userId, true);
})
.catch(() => callback(userId, false));
}
+ async toggleAttentionRequested(type, { user, callback }) {
+ try {
+ const isReviewer = type === 'reviewer';
+ const reviewerOrAssignee = isReviewer
+ ? this.store.findReviewer(user)
+ : this.store.findAssignee(user);
+
+ await this.service.toggleAttentionRequested(user.id);
+
+ if (reviewerOrAssignee.attention_requested) {
+ toast(
+ sprintf(__('Removed attention request from @%{username}'), {
+ username: user.username,
+ }),
+ );
+ } else {
+ toast(sprintf(__('Requested attention from @%{username}'), { username: user.username }));
+ }
+
+ this.store.updateReviewer(user.id, 'attention_requested');
+ this.store.updateAssignee(user.id, 'attention_requested');
+
+ callback();
+ } catch (error) {
+ callback();
+ createFlash({
+ message: sprintf(__('Updating the attention request for %{username} failed.'), {
+ username: user.username,
+ }),
+ error,
+ captureError: true,
+ actionConfig: {
+ title: __('Try again'),
+ clickHandler: () => this.toggleAttentionRequired(type, { user, callback }),
+ },
+ });
+ }
+ }
+
setMoveToProjectId(projectId) {
this.store.setMoveToProjectId(projectId);
}
diff --git a/app/assets/javascripts/sidebar/stores/sidebar_store.js b/app/assets/javascripts/sidebar/stores/sidebar_store.js
index 94c54fc0980..5376791469e 100644
--- a/app/assets/javascripts/sidebar/stores/sidebar_store.js
+++ b/app/assets/javascripts/sidebar/stores/sidebar_store.js
@@ -82,11 +82,19 @@ export default class SidebarStore {
}
}
- updateReviewer(id) {
+ updateAssignee(id, stateKey) {
+ const assignee = this.findAssignee({ id });
+
+ if (assignee) {
+ assignee[stateKey] = !assignee[stateKey];
+ }
+ }
+
+ updateReviewer(id, stateKey) {
const reviewer = this.findReviewer({ id });
if (reviewer) {
- reviewer.reviewed = false;
+ reviewer[stateKey] = !reviewer[stateKey];
}
}