debian-mirror-gitlab/app/assets/javascripts/notes/components/note_actions.vue

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

411 lines
12 KiB
Vue
Raw Normal View History

2018-03-17 18:26:18 +05:30
<script>
2021-01-29 00:20:46 +05:30
import { GlTooltipDirective, GlIcon, GlButton, GlDropdownItem } from '@gitlab/ui';
2022-10-11 01:57:18 +05:30
import { mapActions, mapGetters, mapState } from 'vuex';
2020-06-23 00:09:42 +05:30
import Api from '~/api';
2021-03-11 19:13:27 +05:30
import resolvedStatusMixin from '~/batch_comments/mixins/resolved_status';
2023-05-27 22:25:52 +05:30
import { createAlert } from '~/alert';
2023-04-23 21:23:45 +05:30
import { TYPE_ISSUE } from '~/issues/constants';
2021-03-11 19:13:27 +05:30
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { __, sprintf } from '~/locale';
import eventHub from '~/sidebar/event_hub';
2021-04-17 20:07:23 +05:30
import UserAccessRoleBadge from '~/vue_shared/components/user_access_role_badge.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
2022-06-21 17:19:12 +05:30
import { splitCamelCase } from '~/lib/utils/text_utility';
2023-04-23 21:23:45 +05:30
import AbuseCategorySelector from '~/abuse_reports/components/abuse_category_selector.vue';
2021-03-11 19:13:27 +05:30
import ReplyButton from './note_actions/reply_button.vue';
2022-10-11 01:57:18 +05:30
import TimelineEventButton from './note_actions/timeline_event_button.vue';
2018-03-17 18:26:18 +05:30
2018-05-09 12:01:36 +05:30
export default {
2021-04-29 21:17:54 +05:30
i18n: {
addReactionLabel: __('Add reaction'),
editCommentLabel: __('Edit comment'),
deleteCommentLabel: __('Delete comment'),
moreActionsLabel: __('More actions'),
2023-06-20 00:43:36 +05:30
reportAbuse: __('Report abuse'),
2021-04-29 21:17:54 +05:30
},
2018-05-09 12:01:36 +05:30
name: 'NoteActions',
2018-12-05 23:21:45 +05:30
components: {
2020-11-24 15:15:51 +05:30
GlIcon,
2019-03-02 22:35:43 +05:30
ReplyButton,
2022-10-11 01:57:18 +05:30
TimelineEventButton,
2021-01-29 00:20:46 +05:30
GlButton,
GlDropdownItem,
2021-04-17 20:07:23 +05:30
UserAccessRoleBadge,
EmojiPicker: () => import('~/emoji/components/picker.vue'),
2023-04-23 21:23:45 +05:30
AbuseCategorySelector,
2018-12-05 23:21:45 +05:30
},
2018-05-09 12:01:36 +05:30
directives: {
2019-02-15 15:39:39 +05:30
GlTooltip: GlTooltipDirective,
2018-05-09 12:01:36 +05:30
},
2021-04-17 20:07:23 +05:30
mixins: [resolvedStatusMixin, glFeatureFlagsMixin()],
2018-05-09 12:01:36 +05:30
props: {
2020-06-23 00:09:42 +05:30
author: {
type: Object,
required: true,
},
2018-05-09 12:01:36 +05:30
authorId: {
type: Number,
required: true,
},
noteId: {
2018-12-05 23:21:45 +05:30
type: [String, Number],
2018-05-09 12:01:36 +05:30
required: true,
},
2018-11-08 19:23:39 +05:30
noteUrl: {
type: String,
2018-11-20 20:47:30 +05:30
required: false,
default: '',
2018-11-08 19:23:39 +05:30
},
2018-05-09 12:01:36 +05:30
accessLevel: {
type: String,
required: false,
default: '',
},
2020-11-24 15:15:51 +05:30
isAuthor: {
type: Boolean,
required: false,
default: false,
},
isContributor: {
type: Boolean,
required: false,
default: false,
},
noteableType: {
type: String,
required: false,
default: '',
},
projectName: {
type: String,
required: false,
default: '',
},
2019-03-02 22:35:43 +05:30
showReply: {
type: Boolean,
required: true,
},
2018-05-09 12:01:36 +05:30
canEdit: {
type: Boolean,
required: true,
},
canAwardEmoji: {
type: Boolean,
required: true,
},
canDelete: {
type: Boolean,
required: true,
},
2018-11-08 19:23:39 +05:30
canResolve: {
type: Boolean,
required: false,
default: false,
},
2018-05-09 12:01:36 +05:30
resolvable: {
type: Boolean,
required: false,
default: false,
},
isResolved: {
type: Boolean,
required: false,
default: false,
},
isResolving: {
type: Boolean,
required: false,
default: false,
},
resolvedBy: {
type: Object,
required: false,
default: () => ({}),
},
canReportAsAbuse: {
type: Boolean,
required: true,
},
2021-04-29 21:17:54 +05:30
// This can be undefined when `canAwardEmoji` is false
2021-04-17 20:07:23 +05:30
awardPath: {
type: String,
2021-04-29 21:17:54 +05:30
required: false,
default: '',
2021-04-17 20:07:23 +05:30
},
2018-05-09 12:01:36 +05:30
},
2023-04-23 21:23:45 +05:30
data() {
return {
isReportAbuseDrawerOpen: false,
};
},
2018-05-09 12:01:36 +05:30
computed: {
2022-10-11 01:57:18 +05:30
...mapState(['isPromoteCommentToTimelineEventInProgress']),
...mapGetters(['getUserDataByProp', 'getNoteableData', 'canUserAddIncidentTimelineEvents']),
2018-05-09 12:01:36 +05:30
shouldShowActionsDropdown() {
2023-04-23 21:23:45 +05:30
return this.currentUserId;
2018-05-09 12:01:36 +05:30
},
2018-12-05 23:21:45 +05:30
showDeleteAction() {
return this.canDelete && !this.canReportAsAbuse && !this.noteUrl;
},
2018-05-09 12:01:36 +05:30
isAuthoredByCurrentUser() {
return this.authorId === this.currentUserId;
},
currentUserId() {
return this.getUserDataByProp('id');
},
2020-06-23 00:09:42 +05:30
isUserAssigned() {
return this.assignees && this.assignees.some(({ id }) => id === this.author.id);
},
displayAssignUserText() {
return this.isUserAssigned
? __('Unassign from commenting user')
: __('Assign to commenting user');
},
sidebarAction() {
return this.isUserAssigned ? 'sidebar.addAssignee' : 'sidebar.removeAssignee';
},
targetType() {
return this.getNoteableData.targetType;
},
2020-11-24 15:15:51 +05:30
noteableDisplayName() {
return splitCamelCase(this.noteableType).toLowerCase();
},
2020-06-23 00:09:42 +05:30
assignees() {
return this.getNoteableData.assignees || [];
},
isIssue() {
2023-04-23 21:23:45 +05:30
return this.targetType === TYPE_ISSUE;
2020-06-23 00:09:42 +05:30
},
2020-07-28 23:09:34 +05:30
canAssign() {
2022-08-27 11:52:29 +05:30
return this.getNoteableData.current_user?.can_set_issue_metadata && this.isIssue;
2020-07-28 23:09:34 +05:30
},
2020-11-24 15:15:51 +05:30
displayAuthorBadgeText() {
return sprintf(__('This user is the author of this %{noteable}.'), {
noteable: this.noteableDisplayName,
});
},
displayMemberBadgeText() {
2021-01-03 14:25:43 +05:30
return sprintf(__('This user has the %{access} role in the %{name} project.'), {
2020-11-24 15:15:51 +05:30
access: this.accessLevel.toLowerCase(),
name: this.projectName,
});
},
displayContributorBadgeText() {
return sprintf(__('This user has previously committed to the %{name} project.'), {
name: this.projectName,
});
},
2021-01-29 00:20:46 +05:30
resolveIcon() {
if (!this.isResolving) {
return this.isResolved ? 'check-circle-filled' : 'check-circle';
}
return null;
},
resolveVariant() {
return this.isResolved ? 'success' : 'default';
},
2018-05-09 12:01:36 +05:30
},
methods: {
2022-10-11 01:57:18 +05:30
...mapActions(['toggleAwardRequest', 'promoteCommentToTimelineEvent']),
2018-05-09 12:01:36 +05:30
onEdit() {
this.$emit('handleEdit');
},
onDelete() {
this.$emit('handleDelete');
},
onResolve() {
this.$emit('handleResolve');
},
2019-07-07 11:18:12 +05:30
closeTooltip() {
this.$nextTick(() => {
2021-03-11 19:13:27 +05:30
this.$root.$emit(BV_HIDE_TOOLTIP);
2019-07-07 11:18:12 +05:30
});
},
2020-06-23 00:09:42 +05:30
handleAssigneeUpdate(assignees) {
this.$emit('updateAssignees', assignees);
eventHub.$emit(this.sidebarAction, this.author);
eventHub.$emit('sidebar.saveAssignees');
},
assignUser() {
let { assignees } = this;
const { project_id, iid } = this.getNoteableData;
if (this.isUserAssigned) {
2021-03-08 18:12:59 +05:30
assignees = assignees.filter((assignee) => assignee.id !== this.author.id);
2020-06-23 00:09:42 +05:30
} else {
assignees.push({ id: this.author.id });
}
2023-04-23 21:23:45 +05:30
if (this.targetType === TYPE_ISSUE) {
2020-06-23 00:09:42 +05:30
Api.updateIssue(project_id, iid, {
2021-03-08 18:12:59 +05:30
assignee_ids: assignees.map((assignee) => assignee.id),
2020-06-23 00:09:42 +05:30
})
.then(() => this.handleAssigneeUpdate(assignees))
2021-09-30 23:02:18 +05:30
.catch(() =>
2022-11-25 23:54:43 +05:30
createAlert({
2021-09-30 23:02:18 +05:30
message: __('Something went wrong while updating assignees'),
}),
);
2020-06-23 00:09:42 +05:30
}
},
2021-04-17 20:07:23 +05:30
setAwardEmoji(awardName) {
this.toggleAwardRequest({
endpoint: this.awardPath,
noteId: this.noteId,
awardName,
});
},
2023-04-23 21:23:45 +05:30
toggleReportAbuseDrawer(isOpen) {
this.isReportAbuseDrawerOpen = isOpen;
},
2018-05-09 12:01:36 +05:30
},
};
2018-03-17 18:26:18 +05:30
</script>
<template>
<div class="note-actions">
2021-04-17 20:07:23 +05:30
<user-access-role-badge
2020-11-24 15:15:51 +05:30
v-if="isAuthor"
2021-04-17 20:07:23 +05:30
v-gl-tooltip
2023-04-23 21:23:45 +05:30
class="gl-mr-3 gl-display-none gl-sm-display-block"
2020-11-24 15:15:51 +05:30
:title="displayAuthorBadgeText"
>
2021-04-17 20:07:23 +05:30
{{ __('Author') }}
</user-access-role-badge>
<user-access-role-badge
2020-11-24 15:15:51 +05:30
v-if="accessLevel"
2021-04-17 20:07:23 +05:30
v-gl-tooltip
2023-04-23 21:23:45 +05:30
class="gl-mr-3 gl-display-none gl-sm-display-block"
2020-11-24 15:15:51 +05:30
:title="displayMemberBadgeText"
>
2021-04-17 20:07:23 +05:30
{{ accessLevel }}
</user-access-role-badge>
<user-access-role-badge
2020-11-24 15:15:51 +05:30
v-else-if="isContributor"
2021-04-17 20:07:23 +05:30
v-gl-tooltip
2023-04-23 21:23:45 +05:30
class="gl-mr-3 gl-display-none gl-sm-display-block"
2020-11-24 15:15:51 +05:30
:title="displayContributorBadgeText"
>
2021-04-17 20:07:23 +05:30
{{ __('Contributor') }}
</user-access-role-badge>
2022-11-25 23:54:43 +05:30
<span class="note-actions__mobile-spacer"></span>
2021-03-11 19:13:27 +05:30
<gl-button
v-if="canResolve"
ref="resolveButton"
v-gl-tooltip
category="tertiary"
:variant="resolveVariant"
:class="{ 'is-disabled': !resolvable, 'is-active': isResolved }"
:title="resolveButtonTitle"
:aria-label="resolveButtonTitle"
:icon="resolveIcon"
:loading="isResolving"
class="line-resolve-btn note-action-button"
@click="onResolve"
/>
2022-10-11 01:57:18 +05:30
<timeline-event-button
v-if="canUserAddIncidentTimelineEvents"
:note-id="noteId"
:is-promotion-in-progress="isPromoteCommentToTimelineEventInProgress"
@click-promote-comment-to-event="promoteCommentToTimelineEvent"
/>
2022-06-21 17:19:12 +05:30
<emoji-picker
v-if="canAwardEmoji"
2022-07-23 23:45:48 +05:30
toggle-class="note-action-button note-emoji-button btn-icon btn-default-tertiary"
2022-06-21 17:19:12 +05:30
data-testid="note-emoji-button"
@click="setAwardEmoji"
>
<template #button-content>
2022-07-23 23:45:48 +05:30
<gl-icon class="award-control-icon-neutral gl-button-icon gl-icon" name="slight-smile" />
<gl-icon
class="award-control-icon-positive gl-button-icon gl-icon gl-left-3!"
name="smiley"
/>
<gl-icon
class="award-control-icon-super-positive gl-button-icon gl-icon gl-left-3!"
name="smile"
/>
2022-06-21 17:19:12 +05:30
</template>
</emoji-picker>
2019-03-02 22:35:43 +05:30
<reply-button
2019-07-07 11:18:12 +05:30
v-if="showReply"
2019-03-02 22:35:43 +05:30
ref="replyButton"
class="js-reply-button"
2019-07-07 11:18:12 +05:30
@startReplying="$emit('startReplying')"
2019-03-02 22:35:43 +05:30
/>
2021-03-11 19:13:27 +05:30
<gl-button
v-if="canEdit"
v-gl-tooltip
2021-04-29 21:17:54 +05:30
:title="$options.i18n.editCommentLabel"
:aria-label="$options.i18n.editCommentLabel"
2021-03-11 19:13:27 +05:30
icon="pencil"
category="tertiary"
2023-04-23 21:23:45 +05:30
class="note-action-button js-note-edit gl-display-none gl-sm-display-block"
2021-03-11 19:13:27 +05:30
data-qa-selector="note_edit_button"
@click="onEdit"
/>
<gl-button
v-if="showDeleteAction"
v-gl-tooltip
2021-04-29 21:17:54 +05:30
:title="$options.i18n.deleteCommentLabel"
:aria-label="$options.i18n.deleteCommentLabel"
2021-03-11 19:13:27 +05:30
icon="remove"
category="tertiary"
2021-04-29 21:17:54 +05:30
class="note-action-button js-note-delete"
2021-03-11 19:13:27 +05:30
@click="onDelete"
/>
<div v-else-if="shouldShowActionsDropdown" class="dropdown more-actions">
2021-06-08 01:23:25 +05:30
<!-- eslint-disable @gitlab/vue-no-data-toggle -->
2021-01-29 00:20:46 +05:30
<gl-button
2019-03-02 22:35:43 +05:30
v-gl-tooltip
2021-04-29 21:17:54 +05:30
:title="$options.i18n.moreActionsLabel"
:aria-label="$options.i18n.moreActionsLabel"
2021-01-29 00:20:46 +05:30
icon="ellipsis_v"
category="tertiary"
2021-04-29 21:17:54 +05:30
class="note-action-button more-actions-toggle"
2018-03-17 18:26:18 +05:30
data-toggle="dropdown"
2019-07-07 11:18:12 +05:30
@click="closeTooltip"
2021-01-29 00:20:46 +05:30
/>
2021-06-08 01:23:25 +05:30
<!-- eslint-enable @gitlab/vue-no-data-toggle -->
2023-06-20 00:43:36 +05:30
<ul class="dropdown-menu more-actions-dropdown dropdown-menu-right">
2023-04-23 21:23:45 +05:30
<gl-dropdown-item
v-if="canEdit"
class="js-note-edit gl-sm-display-none!"
@click.prevent="onEdit"
>
{{ __('Edit comment') }}
</gl-dropdown-item>
<gl-dropdown-item
v-if="canReportAsAbuse"
data-testid="report-abuse-button"
@click="toggleReportAbuseDrawer(true)"
>
2023-03-04 22:38:38 +05:30
{{ $options.i18n.reportAbuse }}
2021-01-29 00:20:46 +05:30
</gl-dropdown-item>
<gl-dropdown-item
v-if="noteUrl"
class="js-btn-copy-note-link"
:data-clipboard-text="noteUrl"
>
{{ __('Copy link') }}
</gl-dropdown-item>
<gl-dropdown-item v-if="canAssign" data-testid="assign-user" @click="assignUser">
{{ displayAssignUserText }}
</gl-dropdown-item>
<gl-dropdown-item v-if="canEdit" class="js-note-delete" @click.prevent="onDelete">
<span class="text-danger">{{ __('Delete comment') }}</span>
</gl-dropdown-item>
2018-03-17 18:26:18 +05:30
</ul>
</div>
2023-04-23 21:23:45 +05:30
<!-- IMPORTANT: show this component lazily because it causes layout thrashing -->
<!-- https://gitlab.com/gitlab-org/gitlab/-/issues/331172#note_1269378396 -->
<abuse-category-selector
v-if="canReportAsAbuse && isReportAbuseDrawerOpen"
:reported-user-id="authorId"
:reported-from-url="noteUrl"
:show-drawer="isReportAbuseDrawerOpen"
@close-drawer="toggleReportAbuseDrawer(false)"
/>
2018-03-17 18:26:18 +05:30
</div>
</template>