diff options
Diffstat (limited to 'app/assets')
8 files changed, 97 insertions, 2 deletions
diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index d99694b06e9..394f2a80a67 100644 --- a/app/assets/javascripts/notes/components/note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -2,11 +2,13 @@ import { mapGetters } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui'; +import ReplyButton from './note_actions/reply_button.vue'; export default { name: 'NoteActions', components: { Icon, + ReplyButton, GlLoadingIcon, }, directives: { @@ -21,6 +23,11 @@ export default { type: [String, Number], required: true, }, + discussionId: { + type: String, + required: false, + default: '', + }, noteUrl: { type: String, required: false, @@ -36,6 +43,10 @@ export default { required: false, default: null, }, + showReply: { + type: Boolean, + required: true, + }, canEdit: { type: Boolean, required: true, @@ -80,6 +91,9 @@ export default { }, computed: { ...mapGetters(['getUserDataByProp']), + showReplyButton() { + return gon.features && gon.features.replyToIndividualNotes && this.showReply; + }, shouldShowActionsDropdown() { return this.currentUserId && (this.canEdit || this.canReportAsAbuse); }, @@ -153,6 +167,12 @@ export default { <icon css-classes="link-highlight award-control-icon-super-positive" name="emoji_smiley" /> </a> </div> + <reply-button + v-if="showReplyButton" + ref="replyButton" + class="js-reply-button" + :note-id="discussionId" + /> <div v-if="canEdit" class="note-actions-item"> <button v-gl-tooltip.bottom diff --git a/app/assets/javascripts/notes/components/note_actions/reply_button.vue b/app/assets/javascripts/notes/components/note_actions/reply_button.vue new file mode 100644 index 00000000000..b2f9d7f128a --- /dev/null +++ b/app/assets/javascripts/notes/components/note_actions/reply_button.vue @@ -0,0 +1,40 @@ +<script> +import { mapActions } from 'vuex'; +import { GlTooltipDirective, GlButton } from '@gitlab/ui'; +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + name: 'ReplyButton', + components: { + Icon, + GlButton, + }, + directives: { + GlTooltip: GlTooltipDirective, + }, + props: { + noteId: { + type: String, + required: true, + }, + }, + methods: { + ...mapActions(['convertToDiscussion']), + }, +}; +</script> + +<template> + <div class="note-actions-item"> + <gl-button + ref="button" + v-gl-tooltip.bottom + class="note-action-button" + variant="transparent" + :title="__('Reply to comment')" + @click="convertToDiscussion(noteId)" + > + <icon name="comment" css-classes="link-highlight" /> + </gl-button> + </div> +</template> diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index e26cce1c47f..b7e9f7c2028 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -398,6 +398,7 @@ Please check your network connection and try again.`; :line="line" :commit="commit" :help-page-path="helpPagePath" + :show-reply-button="canReply" @handleDeleteNote="deleteNoteHandler" > <note-edited-text diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index 3c48d81ed05..56108a58010 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -29,6 +29,11 @@ export default { type: Object, required: true, }, + discussion: { + type: Object, + required: false, + default: null, + }, line: { type: Object, required: false, @@ -54,7 +59,7 @@ export default { }; }, computed: { - ...mapGetters(['targetNoteHash', 'getNoteableData', 'getUserData']), + ...mapGetters(['targetNoteHash', 'getNoteableData', 'getUserData', 'commentsDisabled']), author() { return this.note.author; }, @@ -80,6 +85,19 @@ export default { isTarget() { return this.targetNoteHash === this.noteAnchorId; }, + discussionId() { + if (this.discussion) { + return this.discussion.id; + } + return ''; + }, + showReplyButton() { + if (!this.discussion || !this.getNoteableData.current_user.can_create_note) { + return false; + } + + return this.discussion.individual_note && !this.commentsDisabled; + }, actionText() { if (!this.commit) { return ''; @@ -231,6 +249,7 @@ export default { :note-id="note.id" :note-url="note.noteable_note_url" :access-level="note.human_access" + :show-reply="showReplyButton" :can-edit="note.current_user.can_edit" :can-award-emoji="note.current_user.can_award_emoji" :can-delete="note.current_user.can_edit" @@ -241,6 +260,7 @@ export default { :is-resolved="note.resolved" :is-resolving="isResolving" :resolved-by="note.resolved_by" + :discussion-id="discussionId" @handleEdit="editHandler" @handleDelete="deleteHandler" @handleResolve="resolveHandler" diff --git a/app/assets/javascripts/notes/components/notes_app.vue b/app/assets/javascripts/notes/components/notes_app.vue index 5edceea043c..6d72b72e628 100644 --- a/app/assets/javascripts/notes/components/notes_app.vue +++ b/app/assets/javascripts/notes/components/notes_app.vue @@ -199,7 +199,12 @@ export default { :key="discussion.id" :note="discussion.notes[0]" /> - <noteable-note v-else :key="discussion.id" :note="discussion.notes[0]" /> + <noteable-note + v-else + :key="discussion.id" + :note="discussion.notes[0]" + :discussion="discussion" + /> </template> <noteable-discussion v-else diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 2105a62cecb..ff65f14d529 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -426,5 +426,8 @@ export const submitSuggestion = ( }); }; +export const convertToDiscussion = ({ commit }, noteId) => + commit(types.CONVERT_TO_DISCUSSION, noteId); + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/notes/stores/mutation_types.js b/app/assets/javascripts/notes/stores/mutation_types.js index df943c155f4..2bffedad336 100644 --- a/app/assets/javascripts/notes/stores/mutation_types.js +++ b/app/assets/javascripts/notes/stores/mutation_types.js @@ -17,6 +17,7 @@ export const SET_NOTES_FETCHED_STATE = 'SET_NOTES_FETCHED_STATE'; export const SET_NOTES_LOADING_STATE = 'SET_NOTES_LOADING_STATE'; export const DISABLE_COMMENTS = 'DISABLE_COMMENTS'; export const APPLY_SUGGESTION = 'APPLY_SUGGESTION'; +export const CONVERT_TO_DISCUSSION = 'CONVERT_TO_DISCUSSION'; // DISCUSSION export const COLLAPSE_DISCUSSION = 'COLLAPSE_DISCUSSION'; diff --git a/app/assets/javascripts/notes/stores/mutations.js b/app/assets/javascripts/notes/stores/mutations.js index 33d39ad2ec9..d167f8ef421 100644 --- a/app/assets/javascripts/notes/stores/mutations.js +++ b/app/assets/javascripts/notes/stores/mutations.js @@ -264,4 +264,9 @@ export default { ).length; state.hasUnresolvedDiscussions = state.unresolvedDiscussionsCount > 1; }, + + [types.CONVERT_TO_DISCUSSION](state, discussionId) { + const discussion = utils.findNoteObjectById(state.discussions, discussionId); + Object.assign(discussion, { individual_note: false }); + }, }; |