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';
|
2021-04-17 20:07:23 +05:30
|
|
|
import { mapActions, mapGetters } 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';
|
2021-09-30 23:02:18 +05:30
|
|
|
import createFlash from '~/flash';
|
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';
|
2020-11-24 15:15:51 +05:30
|
|
|
import { splitCamelCase } from '../../lib/utils/text_utility';
|
2021-03-11 19:13:27 +05:30
|
|
|
import ReplyButton from './note_actions/reply_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'),
|
|
|
|
},
|
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,
|
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'),
|
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: '',
|
|
|
|
},
|
|
|
|
reportAbusePath: {
|
|
|
|
type: String,
|
2018-12-05 23:21:45 +05:30
|
|
|
required: false,
|
|
|
|
default: null,
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
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
|
|
|
},
|
|
|
|
computed: {
|
2020-06-23 00:09:42 +05:30
|
|
|
...mapGetters(['getUserDataByProp', 'getNoteableData']),
|
2018-05-09 12:01:36 +05:30
|
|
|
shouldShowActionsDropdown() {
|
|
|
|
return this.currentUserId && (this.canEdit || this.canReportAsAbuse);
|
|
|
|
},
|
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() {
|
|
|
|
return this.targetType === 'issue';
|
|
|
|
},
|
2020-07-28 23:09:34 +05:30
|
|
|
canAssign() {
|
|
|
|
return this.getNoteableData.current_user?.can_update && this.isIssue;
|
|
|
|
},
|
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: {
|
2021-04-17 20:07:23 +05:30
|
|
|
...mapActions(['toggleAwardRequest']),
|
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 });
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this.targetType === 'issue') {
|
|
|
|
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(() =>
|
|
|
|
createFlash({
|
|
|
|
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,
|
|
|
|
});
|
|
|
|
},
|
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
|
2021-11-18 22:05:49 +05:30
|
|
|
class="gl-mr-3 d-none d-md-inline-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
|
2021-11-18 22:05:49 +05:30
|
|
|
class="gl-mr-3"
|
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
|
2021-11-18 22:05:49 +05:30
|
|
|
class="gl-mr-3"
|
2020-11-24 15:15:51 +05:30
|
|
|
:title="displayContributorBadgeText"
|
|
|
|
>
|
2021-04-17 20:07:23 +05:30
|
|
|
{{ __('Contributor') }}
|
|
|
|
</user-access-role-badge>
|
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"
|
|
|
|
/>
|
2021-04-17 20:07:23 +05:30
|
|
|
<template v-if="canAwardEmoji">
|
|
|
|
<emoji-picker
|
|
|
|
v-if="glFeatures.improvedEmojiPicker"
|
2021-06-08 01:23:25 +05:30
|
|
|
toggle-class="note-action-button note-emoji-button gl-text-gray-600 gl-m-3 gl-p-0! gl-shadow-none! gl-bg-transparent!"
|
2021-04-17 20:07:23 +05:30
|
|
|
@click="setAwardEmoji"
|
|
|
|
>
|
|
|
|
<template #button-content>
|
|
|
|
<gl-icon class="link-highlight award-control-icon-neutral gl-m-0!" name="slight-smile" />
|
|
|
|
<gl-icon class="link-highlight award-control-icon-positive gl-m-0!" name="smiley" />
|
|
|
|
<gl-icon class="link-highlight award-control-icon-super-positive gl-m-0!" name="smile" />
|
|
|
|
</template>
|
|
|
|
</emoji-picker>
|
|
|
|
<gl-button
|
|
|
|
v-else
|
|
|
|
v-gl-tooltip
|
|
|
|
:class="{ 'js-user-authored': isAuthoredByCurrentUser }"
|
2021-09-04 01:27:46 +05:30
|
|
|
class="note-action-button note-emoji-button add-reaction-button js-add-award js-note-emoji"
|
2021-04-17 20:07:23 +05:30
|
|
|
category="tertiary"
|
|
|
|
variant="default"
|
2021-04-29 21:17:54 +05:30
|
|
|
:title="$options.i18n.addReactionLabel"
|
|
|
|
:aria-label="$options.i18n.addReactionLabel"
|
2021-04-17 20:07:23 +05:30
|
|
|
data-position="right"
|
|
|
|
>
|
|
|
|
<span class="reaction-control-icon reaction-control-icon-neutral">
|
|
|
|
<gl-icon name="slight-smile" />
|
|
|
|
</span>
|
|
|
|
<span class="reaction-control-icon reaction-control-icon-positive">
|
|
|
|
<gl-icon name="smiley" />
|
|
|
|
</span>
|
|
|
|
<span class="reaction-control-icon reaction-control-icon-super-positive">
|
|
|
|
<gl-icon name="smile" />
|
|
|
|
</span>
|
|
|
|
</gl-button>
|
|
|
|
</template>
|
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"
|
2021-04-29 21:17:54 +05:30
|
|
|
class="note-action-button js-note-edit"
|
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 -->
|
2018-03-17 18:26:18 +05:30
|
|
|
<ul class="dropdown-menu more-actions-dropdown dropdown-open-left">
|
2021-01-29 00:20:46 +05:30
|
|
|
<gl-dropdown-item v-if="canReportAsAbuse" :href="reportAbusePath">
|
|
|
|
{{ __('Report abuse to admin') }}
|
|
|
|
</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>
|
|
|
|
</div>
|
|
|
|
</template>
|