summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/work_items/components/notes/work_item_discussion.vue')
-rw-r--r--app/assets/javascripts/work_items/components/notes/work_item_discussion.vue191
1 files changed, 191 insertions, 0 deletions
diff --git a/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
new file mode 100644
index 00000000000..bda00f978b9
--- /dev/null
+++ b/app/assets/javascripts/work_items/components/notes/work_item_discussion.vue
@@ -0,0 +1,191 @@
+<script>
+import { GlAvatarLink, GlAvatar } from '@gitlab/ui';
+import { ASC } from '~/notes/constants';
+import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue';
+import DiscussionNotesRepliesWrapper from '~/notes/components/discussion_notes_replies_wrapper.vue';
+import ToggleRepliesWidget from '~/notes/components/toggle_replies_widget.vue';
+import WorkItemNote from '~/work_items/components/notes/work_item_note.vue';
+import WorkItemNoteReplying from '~/work_items/components/notes/work_item_note_replying.vue';
+import WorkItemAddNote from './work_item_add_note.vue';
+
+export default {
+ components: {
+ TimelineEntryItem,
+ GlAvatarLink,
+ GlAvatar,
+ WorkItemNote,
+ WorkItemAddNote,
+ ToggleRepliesWidget,
+ DiscussionNotesRepliesWrapper,
+ WorkItemNoteReplying,
+ },
+ props: {
+ workItemId: {
+ type: String,
+ required: true,
+ },
+ queryVariables: {
+ type: Object,
+ required: true,
+ },
+ fullPath: {
+ type: String,
+ required: true,
+ },
+ workItemType: {
+ type: String,
+ required: true,
+ },
+ fetchByIid: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ discussion: {
+ type: Array,
+ required: true,
+ },
+ sortOrder: {
+ type: String,
+ default: ASC,
+ required: false,
+ },
+ },
+ data() {
+ return {
+ isExpanded: false,
+ autofocus: false,
+ isReplying: false,
+ replyingText: '',
+ };
+ },
+ computed: {
+ note() {
+ return this.discussion[0];
+ },
+ author() {
+ return this.note.author;
+ },
+ noteAnchorId() {
+ return `note_${this.note.id}`;
+ },
+ hasReplies() {
+ return this.replies?.length;
+ },
+ replies() {
+ if (this.discussion?.length > 1) {
+ return this.discussion.slice(1);
+ }
+ return null;
+ },
+ discussionId() {
+ return this.discussion[0]?.discussion?.id || '';
+ },
+ },
+ methods: {
+ showReplyForm() {
+ this.isExpanded = true;
+ this.autofocus = true;
+ },
+ hideReplyForm() {
+ this.isExpanded = this.hasReplies;
+ this.autofocus = false;
+ },
+ toggleDiscussion() {
+ this.isExpanded = !this.isExpanded;
+ this.autofocus = this.isExpanded;
+ },
+ threadKey(note) {
+ /* eslint-disable @gitlab/require-i18n-strings */
+ return `${note.id}-thread`;
+ },
+ onReplied() {
+ this.isExpanded = true;
+ this.isReplying = false;
+ this.replyingText = '';
+ },
+ onReplying(commentText) {
+ this.isReplying = true;
+ this.replyingText = commentText;
+ },
+ },
+};
+</script>
+
+<template>
+ <timeline-entry-item
+ :id="noteAnchorId"
+ :class="{ 'internal-note': note.internal }"
+ :data-note-id="note.id"
+ class="note note-wrapper note-comment gl-px-0"
+ >
+ <div class="timeline-avatar gl-float-left">
+ <gl-avatar-link :href="author.webUrl">
+ <gl-avatar
+ :src="author.avatarUrl"
+ :entity-name="author.username"
+ :alt="author.name"
+ :size="32"
+ />
+ </gl-avatar-link>
+ </div>
+
+ <div class="timeline-content">
+ <div class="discussion-body">
+ <div class="discussion-wrapper">
+ <div class="discussion-notes">
+ <ul class="notes">
+ <work-item-note
+ :is-first-note="true"
+ :note="note"
+ :discussion-id="discussionId"
+ :work-item-type="workItemType"
+ :class="{ 'gl-mb-5': hasReplies }"
+ @startReplying="showReplyForm"
+ @deleteNote="$emit('deleteNote', note)"
+ @error="$emit('error', $event)"
+ />
+ <discussion-notes-replies-wrapper>
+ <toggle-replies-widget
+ v-if="hasReplies"
+ :collapsed="!isExpanded"
+ :replies="replies"
+ @toggle="toggleDiscussion({ discussionId })"
+ />
+ <template v-if="isExpanded">
+ <template v-for="reply in replies">
+ <work-item-note
+ :key="threadKey(reply)"
+ :discussion-id="discussionId"
+ :note="reply"
+ :work-item-type="workItemType"
+ @startReplying="showReplyForm"
+ @deleteNote="$emit('deleteNote', reply)"
+ @error="$emit('error', $event)"
+ />
+ </template>
+ <work-item-note-replying v-if="isReplying" :body="replyingText" />
+ <work-item-add-note
+ :autofocus="autofocus"
+ :query-variables="queryVariables"
+ :full-path="fullPath"
+ :work-item-id="workItemId"
+ :fetch-by-iid="fetchByIid"
+ :discussion-id="discussionId"
+ :work-item-type="workItemType"
+ :sort-order="sortOrder"
+ :add-padding="true"
+ @cancelEditing="hideReplyForm"
+ @replied="onReplied"
+ @replying="onReplying"
+ @error="$emit('error', $event)"
+ />
+ </template>
+ </discussion-notes-replies-wrapper>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </timeline-entry-item>
+</template>