2018-03-17 18:26:18 +05:30
|
|
|
<script>
|
2019-02-15 15:39:39 +05:30
|
|
|
import _ from 'underscore';
|
2018-05-09 12:01:36 +05:30
|
|
|
import { mapActions, mapGetters } from 'vuex';
|
2019-02-15 15:39:39 +05:30
|
|
|
import { GlTooltipDirective } from '@gitlab/ui';
|
2018-11-08 19:23:39 +05:30
|
|
|
import { truncateSha } from '~/lib/utils/text_utility';
|
2019-02-15 15:39:39 +05:30
|
|
|
import { s__, __, sprintf } from '~/locale';
|
2018-12-13 13:39:08 +05:30
|
|
|
import systemNote from '~/vue_shared/components/notes/system_note.vue';
|
|
|
|
import icon from '~/vue_shared/components/icon.vue';
|
2019-02-15 15:39:39 +05:30
|
|
|
import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
|
2018-05-09 12:01:36 +05:30
|
|
|
import Flash from '../../flash';
|
|
|
|
import { SYSTEM_NOTE } from '../constants';
|
|
|
|
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
|
|
|
|
import noteableNote from './noteable_note.vue';
|
|
|
|
import noteHeader from './note_header.vue';
|
2018-12-13 13:39:08 +05:30
|
|
|
import toggleRepliesWidget from './toggle_replies_widget.vue';
|
2018-05-09 12:01:36 +05:30
|
|
|
import noteSignedOutWidget from './note_signed_out_widget.vue';
|
|
|
|
import noteEditedText from './note_edited_text.vue';
|
|
|
|
import noteForm from './note_form.vue';
|
|
|
|
import diffWithNote from './diff_with_note.vue';
|
|
|
|
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
|
|
|
|
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
|
|
|
|
import autosave from '../mixins/autosave';
|
|
|
|
import noteable from '../mixins/noteable';
|
|
|
|
import resolvable from '../mixins/resolvable';
|
2018-11-18 11:00:15 +05:30
|
|
|
import discussionNavigation from '../mixins/discussion_navigation';
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
export default {
|
2018-11-08 19:23:39 +05:30
|
|
|
name: 'NoteableDiscussion',
|
2018-05-09 12:01:36 +05:30
|
|
|
components: {
|
2018-12-13 13:39:08 +05:30
|
|
|
icon,
|
2018-05-09 12:01:36 +05:30
|
|
|
noteableNote,
|
|
|
|
userAvatarLink,
|
|
|
|
noteHeader,
|
|
|
|
noteSignedOutWidget,
|
|
|
|
noteEditedText,
|
|
|
|
noteForm,
|
2018-12-13 13:39:08 +05:30
|
|
|
toggleRepliesWidget,
|
2018-05-09 12:01:36 +05:30
|
|
|
placeholderNote,
|
|
|
|
placeholderSystemNote,
|
2018-11-08 19:23:39 +05:30
|
|
|
systemNote,
|
2019-02-15 15:39:39 +05:30
|
|
|
TimelineEntryItem,
|
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
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
mixins: [autosave, noteable, resolvable, discussionNavigation],
|
2018-05-09 12:01:36 +05:30
|
|
|
props: {
|
2018-11-08 19:23:39 +05:30
|
|
|
discussion: {
|
2018-05-09 12:01:36 +05:30
|
|
|
type: Object,
|
|
|
|
required: true,
|
|
|
|
},
|
2019-02-15 15:39:39 +05:30
|
|
|
line: {
|
|
|
|
type: Object,
|
|
|
|
required: false,
|
|
|
|
default: null,
|
|
|
|
},
|
2018-11-08 19:23:39 +05:30
|
|
|
renderDiffFile: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
alwaysExpanded: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
discussionsByDiffOrder: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: false,
|
|
|
|
},
|
2019-02-15 15:39:39 +05:30
|
|
|
helpPagePath: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: '',
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
data() {
|
2019-02-15 15:39:39 +05:30
|
|
|
const { diff_discussion: isDiffDiscussion, resolved } = this.discussion;
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
return {
|
|
|
|
isReplying: false,
|
|
|
|
isResolving: false,
|
|
|
|
resolveAsThread: true,
|
2019-02-15 15:39:39 +05:30
|
|
|
isRepliesCollapsed: Boolean(!isDiffDiscussion && resolved),
|
2018-05-09 12:01:36 +05:30
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
...mapGetters([
|
|
|
|
'getNoteableData',
|
2018-11-18 11:00:15 +05:30
|
|
|
'nextUnresolvedDiscussionId',
|
2019-02-15 15:39:39 +05:30
|
|
|
'unresolvedDiscussionsCount',
|
|
|
|
'hasUnresolvedDiscussions',
|
|
|
|
'showJumpToNextDiscussion',
|
2018-05-09 12:01:36 +05:30
|
|
|
]),
|
|
|
|
author() {
|
2019-02-15 15:39:39 +05:30
|
|
|
return this.initialDiscussion.author;
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
canReply() {
|
|
|
|
return this.getNoteableData.current_user.can_create_note;
|
|
|
|
},
|
|
|
|
newNotePath() {
|
|
|
|
return this.getNoteableData.create_note_path;
|
|
|
|
},
|
2018-12-13 13:39:08 +05:30
|
|
|
hasReplies() {
|
|
|
|
return this.discussion.notes.length > 1;
|
|
|
|
},
|
|
|
|
initialDiscussion() {
|
|
|
|
return this.discussion.notes.slice(0, 1)[0];
|
|
|
|
},
|
|
|
|
replies() {
|
|
|
|
return this.discussion.notes.slice(1);
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
lastUpdatedBy() {
|
2018-11-08 19:23:39 +05:30
|
|
|
const { notes } = this.discussion;
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
if (notes.length > 1) {
|
|
|
|
return notes[notes.length - 1].author;
|
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
return null;
|
|
|
|
},
|
|
|
|
lastUpdatedAt() {
|
2018-11-08 19:23:39 +05:30
|
|
|
const { notes } = this.discussion;
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
if (notes.length > 1) {
|
|
|
|
return notes[notes.length - 1].created_at;
|
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
return null;
|
|
|
|
},
|
2018-11-08 19:23:39 +05:30
|
|
|
resolvedText() {
|
2019-02-15 15:39:39 +05:30
|
|
|
return this.discussion.resolved_by_push ? __('Automatically resolved') : __('Resolved');
|
2019-01-03 12:48:30 +05:30
|
|
|
},
|
2019-02-15 15:39:39 +05:30
|
|
|
shouldShowJumpToNextDiscussion() {
|
|
|
|
return this.showJumpToNextDiscussion(
|
|
|
|
this.discussion.id,
|
|
|
|
this.discussionsByDiffOrder ? 'diff' : 'discussion',
|
2018-11-20 20:47:30 +05:30
|
|
|
);
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
2018-11-08 19:23:39 +05:30
|
|
|
shouldRenderDiffs() {
|
2019-02-15 15:39:39 +05:30
|
|
|
return this.discussion.diff_discussion && this.renderDiffFile;
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
2018-12-13 13:39:08 +05:30
|
|
|
shouldGroupReplies() {
|
2019-02-15 15:39:39 +05:30
|
|
|
return !this.shouldRenderDiffs && !this.discussion.diff_discussion;
|
2018-12-13 13:39:08 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
wrapperComponent() {
|
2018-11-08 19:23:39 +05:30
|
|
|
return this.shouldRenderDiffs ? diffWithNote : 'div';
|
|
|
|
},
|
|
|
|
wrapperComponentProps() {
|
|
|
|
if (this.shouldRenderDiffs) {
|
2019-02-15 15:39:39 +05:30
|
|
|
return { discussion: this.discussion };
|
2018-11-08 19:23:39 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
return {};
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
2018-12-13 13:39:08 +05:30
|
|
|
componentClassName() {
|
|
|
|
if (this.shouldRenderDiffs) {
|
|
|
|
if (!this.lastUpdatedAt && !this.discussion.resolved) {
|
|
|
|
return 'unresolved';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return '';
|
|
|
|
},
|
|
|
|
shouldShowDiscussions() {
|
2019-02-15 15:39:39 +05:30
|
|
|
const { expanded, resolved } = this.discussion;
|
|
|
|
const isResolvedNonDiffDiscussion = !this.discussion.diff_discussion && resolved;
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
return expanded || this.alwaysExpanded || isResolvedNonDiffDiscussion;
|
2018-12-13 13:39:08 +05:30
|
|
|
},
|
2019-02-15 15:39:39 +05:30
|
|
|
actionText() {
|
|
|
|
const linkStart = `<a href="${_.escape(this.discussion.discussion_path)}">`;
|
|
|
|
const linkEnd = '</a>';
|
2018-12-13 13:39:08 +05:30
|
|
|
|
2019-02-15 15:39:39 +05:30
|
|
|
let { commit_id: commitId } = this.discussion;
|
|
|
|
if (commitId) {
|
|
|
|
commitId = `<span class="commit-sha">${truncateSha(commitId)}</span>`;
|
|
|
|
}
|
|
|
|
|
|
|
|
const {
|
|
|
|
for_commit: isForCommit,
|
|
|
|
diff_discussion: isDiffDiscussion,
|
|
|
|
active: isActive,
|
|
|
|
} = this.discussion;
|
|
|
|
|
|
|
|
let text = s__('MergeRequests|started a discussion');
|
|
|
|
if (isForCommit) {
|
|
|
|
text = s__(
|
|
|
|
'MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}',
|
|
|
|
);
|
|
|
|
} else if (isDiffDiscussion && commitId) {
|
|
|
|
text = isActive
|
|
|
|
? s__('MergeRequests|started a discussion on commit %{linkStart}%{commitId}%{linkEnd}')
|
|
|
|
: s__(
|
|
|
|
'MergeRequests|started a discussion on an outdated change in commit %{linkStart}%{commitId}%{linkEnd}',
|
|
|
|
);
|
|
|
|
} else if (isDiffDiscussion) {
|
|
|
|
text = isActive
|
|
|
|
? s__('MergeRequests|started a discussion on %{linkStart}the diff%{linkEnd}')
|
|
|
|
: s__(
|
|
|
|
'MergeRequests|started a discussion on %{linkStart}an old version of the diff%{linkEnd}',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sprintf(text, { commitId, linkStart, linkEnd }, false);
|
|
|
|
},
|
|
|
|
diffLine() {
|
|
|
|
if (this.discussion.diff_discussion && this.discussion.truncated_diff_lines) {
|
|
|
|
return this.discussion.truncated_diff_lines.slice(-1)[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.line;
|
2018-12-13 13:39:08 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
watch: {
|
|
|
|
isReplying() {
|
|
|
|
if (this.isReplying) {
|
|
|
|
this.$nextTick(() => {
|
|
|
|
// Pass an extra key to separate reply and note edit forms
|
2019-02-15 15:39:39 +05:30
|
|
|
this.initAutoSave({ ...this.initialDiscussion, ...this.discussion }, ['Reply']);
|
2018-11-18 11:00:15 +05:30
|
|
|
});
|
2018-05-09 12:01:36 +05:30
|
|
|
} else {
|
2018-11-18 11:00:15 +05:30
|
|
|
this.disposeAutoSave();
|
2018-03-17 18:26:18 +05:30
|
|
|
}
|
2018-11-18 11:00:15 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
...mapActions([
|
|
|
|
'saveNote',
|
|
|
|
'toggleDiscussion',
|
|
|
|
'removePlaceholderNotes',
|
|
|
|
'toggleResolveNote',
|
2018-11-08 19:23:39 +05:30
|
|
|
'expandDiscussion',
|
2018-05-09 12:01:36 +05:30
|
|
|
]),
|
2018-11-08 19:23:39 +05:30
|
|
|
truncateSha,
|
2018-05-09 12:01:36 +05:30
|
|
|
componentName(note) {
|
|
|
|
if (note.isPlaceholderNote) {
|
|
|
|
if (note.placeholderType === SYSTEM_NOTE) {
|
|
|
|
return placeholderSystemNote;
|
2018-03-17 18:26:18 +05:30
|
|
|
}
|
2018-12-05 23:21:45 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
return placeholderNote;
|
2018-03-17 18:26:18 +05:30
|
|
|
}
|
2018-05-09 12:01:36 +05:30
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
if (note.system) {
|
|
|
|
return systemNote;
|
|
|
|
}
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
return noteableNote;
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
componentData(note) {
|
2018-12-05 23:21:45 +05:30
|
|
|
return note.isPlaceholderNote ? note.notes[0] : note;
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
toggleDiscussionHandler() {
|
2018-11-08 19:23:39 +05:30
|
|
|
this.toggleDiscussion({ discussionId: this.discussion.id });
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
2018-12-13 13:39:08 +05:30
|
|
|
toggleReplies() {
|
2019-02-15 15:39:39 +05:30
|
|
|
this.isRepliesCollapsed = !this.isRepliesCollapsed;
|
2018-12-13 13:39:08 +05:30
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
showReplyForm() {
|
|
|
|
this.isReplying = true;
|
|
|
|
},
|
2018-11-18 11:00:15 +05:30
|
|
|
cancelReplyForm(shouldConfirm, isDirty) {
|
|
|
|
if (shouldConfirm && isDirty) {
|
|
|
|
const msg = s__('Notes|Are you sure you want to cancel creating this comment?');
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
// eslint-disable-next-line no-alert
|
2018-11-18 11:00:15 +05:30
|
|
|
if (!window.confirm(msg)) {
|
2018-05-09 12:01:36 +05:30
|
|
|
return;
|
2018-03-17 18:26:18 +05:30
|
|
|
}
|
2018-05-09 12:01:36 +05:30
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
this.isReplying = false;
|
2018-11-18 11:00:15 +05:30
|
|
|
this.resetAutoSave();
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
saveReply(noteText, form, callback) {
|
2018-11-08 19:23:39 +05:30
|
|
|
const postData = {
|
|
|
|
in_reply_to_discussion_id: this.discussion.reply_id,
|
|
|
|
target_type: this.getNoteableData.targetType,
|
|
|
|
note: { note: noteText },
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.discussion.for_commit) {
|
|
|
|
postData.note_project_id = this.discussion.project_id;
|
|
|
|
}
|
|
|
|
|
2018-05-09 12:01:36 +05:30
|
|
|
const replyData = {
|
|
|
|
endpoint: this.newNotePath,
|
|
|
|
flashContainer: this.$el,
|
2018-11-08 19:23:39 +05:30
|
|
|
data: postData,
|
2018-05-09 12:01:36 +05:30
|
|
|
};
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2018-11-08 19:23:39 +05:30
|
|
|
this.isReplying = false;
|
2018-05-09 12:01:36 +05:30
|
|
|
this.saveNote(replyData)
|
|
|
|
.then(() => {
|
|
|
|
this.resetAutoSave();
|
|
|
|
callback();
|
|
|
|
})
|
|
|
|
.catch(err => {
|
|
|
|
this.removePlaceholderNotes();
|
|
|
|
this.isReplying = true;
|
|
|
|
this.$nextTick(() => {
|
|
|
|
const msg = `Your comment could not be submitted!
|
2018-03-17 18:26:18 +05:30
|
|
|
Please check your network connection and try again.`;
|
2018-05-09 12:01:36 +05:30
|
|
|
Flash(msg, 'alert', this.$el);
|
|
|
|
this.$refs.noteForm.note = noteText;
|
|
|
|
callback(err);
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
2018-05-09 12:01:36 +05:30
|
|
|
});
|
|
|
|
},
|
2018-11-08 19:23:39 +05:30
|
|
|
jumpToNextDiscussion() {
|
2018-11-20 20:47:30 +05:30
|
|
|
const nextId = this.nextUnresolvedDiscussionId(
|
|
|
|
this.discussion.id,
|
|
|
|
this.discussionsByDiffOrder,
|
|
|
|
);
|
2018-03-27 19:54:05 +05:30
|
|
|
|
2018-11-18 11:00:15 +05:30
|
|
|
this.jumpToDiscussion(nextId);
|
2018-03-17 18:26:18 +05:30
|
|
|
},
|
2018-11-20 20:47:30 +05:30
|
|
|
deleteNoteHandler(note) {
|
|
|
|
this.$emit('noteDeleted', this.discussion, note);
|
|
|
|
},
|
2018-05-09 12:01:36 +05:30
|
|
|
},
|
|
|
|
};
|
2018-03-17 18:26:18 +05:30
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2019-02-15 15:39:39 +05:30
|
|
|
<timeline-entry-item class="note note-discussion" :class="componentClassName">
|
|
|
|
<div class="timeline-content">
|
|
|
|
<div :data-discussion-id="discussion.id" class="discussion js-discussion-container">
|
|
|
|
<div v-if="shouldRenderDiffs" class="discussion-header note-wrapper">
|
|
|
|
<div v-once class="timeline-icon">
|
|
|
|
<user-avatar-link
|
|
|
|
v-if="author"
|
|
|
|
:link-href="author.path"
|
|
|
|
:img-src="author.avatar_url"
|
|
|
|
:img-alt="author.name"
|
|
|
|
:img-size="40"
|
2018-03-17 18:26:18 +05:30
|
|
|
/>
|
|
|
|
</div>
|
2019-02-15 15:39:39 +05:30
|
|
|
<note-header
|
|
|
|
:author="author"
|
|
|
|
:created-at="initialDiscussion.created_at"
|
|
|
|
:note-id="initialDiscussion.id"
|
|
|
|
:include-toggle="true"
|
|
|
|
:expanded="discussion.expanded"
|
|
|
|
@toggleHandler="toggleDiscussionHandler"
|
|
|
|
>
|
|
|
|
<span v-html="actionText"></span>
|
|
|
|
</note-header>
|
|
|
|
<note-edited-text
|
|
|
|
v-if="discussion.resolved"
|
|
|
|
:edited-at="discussion.resolved_at"
|
|
|
|
:edited-by="discussion.resolved_by"
|
|
|
|
:action-text="resolvedText"
|
|
|
|
class-name="discussion-headline-light js-discussion-headline"
|
|
|
|
/>
|
|
|
|
<note-edited-text
|
|
|
|
v-else-if="lastUpdatedAt"
|
|
|
|
:edited-at="lastUpdatedAt"
|
|
|
|
:edited-by="lastUpdatedBy"
|
|
|
|
action-text="Last updated"
|
|
|
|
class-name="discussion-headline-light js-discussion-headline"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div v-if="shouldShowDiscussions" class="discussion-body">
|
|
|
|
<component
|
|
|
|
:is="wrapperComponent"
|
|
|
|
v-bind="wrapperComponentProps"
|
|
|
|
class="card discussion-wrapper"
|
|
|
|
>
|
|
|
|
<div class="discussion-notes">
|
|
|
|
<ul class="notes">
|
|
|
|
<template v-if="shouldGroupReplies">
|
|
|
|
<component
|
|
|
|
:is="componentName(initialDiscussion)"
|
|
|
|
:note="componentData(initialDiscussion)"
|
|
|
|
:line="line"
|
|
|
|
:help-page-path="helpPagePath"
|
|
|
|
@handleDeleteNote="deleteNoteHandler"
|
|
|
|
>
|
|
|
|
<note-edited-text
|
|
|
|
v-if="discussion.resolved"
|
|
|
|
slot="discussion-resolved-text"
|
|
|
|
:edited-at="discussion.resolved_at"
|
|
|
|
:edited-by="discussion.resolved_by"
|
|
|
|
:action-text="resolvedText"
|
|
|
|
class-name="discussion-headline-light js-discussion-headline discussion-resolved-text"
|
2019-01-03 12:48:30 +05:30
|
|
|
/>
|
2019-02-15 15:39:39 +05:30
|
|
|
<slot slot="avatar-badge" name="avatar-badge"></slot>
|
|
|
|
</component>
|
|
|
|
<toggle-replies-widget
|
|
|
|
v-if="hasReplies"
|
|
|
|
:collapsed="isRepliesCollapsed"
|
|
|
|
:replies="replies"
|
|
|
|
@toggle="toggleReplies"
|
|
|
|
/>
|
|
|
|
<template v-if="!isRepliesCollapsed">
|
2018-12-13 13:39:08 +05:30
|
|
|
<component
|
|
|
|
:is="componentName(note)"
|
2019-02-15 15:39:39 +05:30
|
|
|
v-for="note in replies"
|
2018-12-13 13:39:08 +05:30
|
|
|
:key="note.id"
|
|
|
|
:note="componentData(note)"
|
2019-02-15 15:39:39 +05:30
|
|
|
:help-page-path="helpPagePath"
|
|
|
|
:line="line"
|
2018-12-13 13:39:08 +05:30
|
|
|
@handleDeleteNote="deleteNoteHandler"
|
2019-02-15 15:39:39 +05:30
|
|
|
/>
|
2019-01-03 12:48:30 +05:30
|
|
|
</template>
|
2019-02-15 15:39:39 +05:30
|
|
|
</template>
|
|
|
|
<template v-else>
|
|
|
|
<component
|
|
|
|
:is="componentName(note)"
|
|
|
|
v-for="(note, index) in discussion.notes"
|
|
|
|
:key="note.id"
|
|
|
|
:note="componentData(note)"
|
|
|
|
:help-page-path="helpPagePath"
|
|
|
|
:line="diffLine"
|
|
|
|
@handleDeleteNote="deleteNoteHandler"
|
|
|
|
>
|
|
|
|
<slot v-if="index === 0" slot="avatar-badge" name="avatar-badge"></slot>
|
|
|
|
</component>
|
|
|
|
</template>
|
|
|
|
</ul>
|
|
|
|
<div
|
|
|
|
v-if="!isRepliesCollapsed || !hasReplies"
|
|
|
|
:class="{ 'is-replying': isReplying }"
|
|
|
|
class="discussion-reply-holder"
|
|
|
|
>
|
|
|
|
<template v-if="!isReplying && canReply">
|
|
|
|
<div class="discussion-with-resolve-btn">
|
|
|
|
<button
|
|
|
|
type="button"
|
|
|
|
class="js-vue-discussion-reply btn btn-text-field qa-discussion-reply"
|
|
|
|
title="Add a reply"
|
|
|
|
@click="showReplyForm"
|
|
|
|
>
|
|
|
|
Reply...
|
|
|
|
</button>
|
|
|
|
<div v-if="discussion.resolvable">
|
2018-12-13 13:39:08 +05:30
|
|
|
<button
|
|
|
|
type="button"
|
2019-02-15 15:39:39 +05:30
|
|
|
class="btn btn-default ml-sm-2"
|
|
|
|
@click="resolveHandler();"
|
2018-12-13 13:39:08 +05:30
|
|
|
>
|
2019-02-15 15:39:39 +05:30
|
|
|
<i v-if="isResolving" aria-hidden="true" class="fa fa-spinner fa-spin"></i>
|
|
|
|
{{ resolveButtonTitle }}
|
2018-12-13 13:39:08 +05:30
|
|
|
</button>
|
2019-02-15 15:39:39 +05:30
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-if="discussion.resolvable"
|
|
|
|
class="btn-group discussion-actions ml-sm-2"
|
|
|
|
role="group"
|
|
|
|
>
|
|
|
|
<div v-if="!discussionResolved" class="btn-group" role="group">
|
|
|
|
<a
|
|
|
|
v-gl-tooltip
|
|
|
|
:href="discussion.resolve_with_issue_path"
|
|
|
|
:title="s__('MergeRequests|Resolve this discussion in a new issue')"
|
|
|
|
class="new-issue-for-discussion btn btn-default discussion-create-issue-btn"
|
|
|
|
>
|
|
|
|
<icon name="issue-new" />
|
|
|
|
</a>
|
|
|
|
</div>
|
|
|
|
<div v-if="shouldShowJumpToNextDiscussion" class="btn-group" role="group">
|
2018-03-27 19:54:05 +05:30
|
|
|
<button
|
2019-02-15 15:39:39 +05:30
|
|
|
v-gl-tooltip
|
|
|
|
class="btn btn-default discussion-next-btn"
|
|
|
|
title="Jump to next unresolved discussion"
|
|
|
|
@click="jumpToNextDiscussion"
|
2018-03-27 19:54:05 +05:30
|
|
|
>
|
2019-02-15 15:39:39 +05:30
|
|
|
<icon name="comment-next" />
|
2018-03-27 19:54:05 +05:30
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
2019-02-15 15:39:39 +05:30
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<note-form
|
|
|
|
v-if="isReplying"
|
|
|
|
ref="noteForm"
|
|
|
|
:discussion="discussion"
|
|
|
|
:is-editing="false"
|
|
|
|
:line="diffLine"
|
|
|
|
save-button-title="Comment"
|
|
|
|
@handleFormUpdate="saveReply"
|
|
|
|
@cancelForm="cancelReplyForm"
|
|
|
|
/>
|
|
|
|
<note-signed-out-widget v-if="!canReply" />
|
2018-03-17 18:26:18 +05:30
|
|
|
</div>
|
2019-02-15 15:39:39 +05:30
|
|
|
</div>
|
|
|
|
</component>
|
2018-03-17 18:26:18 +05:30
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2019-02-15 15:39:39 +05:30
|
|
|
</timeline-entry-item>
|
2018-03-17 18:26:18 +05:30
|
|
|
</template>
|