2017-06-09 18:50:31 -04:00
|
|
|
<script>
|
2018-03-16 16:16:21 -04:00
|
|
|
import { mapGetters, mapActions } from 'vuex';
|
|
|
|
import { getLocationHash } from '../../lib/utils/url_utility';
|
|
|
|
import Flash from '../../flash';
|
|
|
|
import * as constants from '../constants';
|
2018-06-29 03:22:07 -04:00
|
|
|
import eventHub from '../event_hub';
|
2018-03-16 16:16:21 -04:00
|
|
|
import noteableNote from './noteable_note.vue';
|
|
|
|
import noteableDiscussion from './noteable_discussion.vue';
|
2019-02-26 09:04:15 -05:00
|
|
|
import discussionFilterNote from './discussion_filter_note.vue';
|
2018-03-16 16:16:21 -04:00
|
|
|
import systemNote from '../../vue_shared/components/notes/system_note.vue';
|
|
|
|
import commentForm from './comment_form.vue';
|
|
|
|
import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue';
|
|
|
|
import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue';
|
|
|
|
import skeletonLoadingContainer from '../../vue_shared/components/notes/skeleton_note.vue';
|
2018-08-28 12:19:52 -04:00
|
|
|
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
|
2018-12-07 22:12:23 -05:00
|
|
|
import initUserPopovers from '../../user_popovers';
|
2017-06-09 18:50:31 -04:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
export default {
|
|
|
|
name: 'NotesApp',
|
|
|
|
components: {
|
|
|
|
noteableNote,
|
|
|
|
noteableDiscussion,
|
|
|
|
systemNote,
|
|
|
|
commentForm,
|
|
|
|
placeholderNote,
|
|
|
|
placeholderSystemNote,
|
2018-11-09 04:44:07 -05:00
|
|
|
skeletonLoadingContainer,
|
2019-02-26 09:04:15 -05:00
|
|
|
discussionFilterNote,
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
props: {
|
|
|
|
noteableData: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
2018-01-04 19:18:35 -05:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
notesData: {
|
|
|
|
type: Object,
|
|
|
|
required: true,
|
2017-07-27 16:24:05 -04:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
userData: {
|
|
|
|
type: Object,
|
|
|
|
required: false,
|
|
|
|
default: () => ({}),
|
2017-06-13 13:01:59 -04:00
|
|
|
},
|
2018-06-21 08:22:40 -04:00
|
|
|
shouldShow: {
|
|
|
|
type: Boolean,
|
|
|
|
required: false,
|
|
|
|
default: true,
|
|
|
|
},
|
2018-12-13 14:17:19 -05:00
|
|
|
helpPagePath: {
|
|
|
|
type: String,
|
|
|
|
required: false,
|
|
|
|
default: '',
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2018-11-08 05:42:11 -05:00
|
|
|
isFetching: false,
|
2018-10-23 05:49:45 -04:00
|
|
|
currentFilter: null,
|
2018-03-16 16:16:21 -04:00
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
2018-10-30 16:28:31 -04:00
|
|
|
...mapGetters([
|
|
|
|
'isNotesFetched',
|
|
|
|
'discussions',
|
2019-02-14 05:07:13 -05:00
|
|
|
'convertedDisscussionIds',
|
2018-10-30 16:28:31 -04:00
|
|
|
'getNotesDataByProp',
|
|
|
|
'isLoading',
|
2018-11-05 07:30:14 -05:00
|
|
|
'commentsDisabled',
|
2019-02-18 04:43:13 -05:00
|
|
|
'getNoteableData',
|
2019-05-01 06:04:07 -04:00
|
|
|
'userCanReply',
|
2018-10-30 16:28:31 -04:00
|
|
|
]),
|
2018-03-16 16:16:21 -04:00
|
|
|
noteableType() {
|
2018-04-05 04:26:54 -04:00
|
|
|
return this.noteableData.noteableType;
|
2018-01-04 19:18:35 -05:00
|
|
|
},
|
2018-06-21 08:22:40 -04:00
|
|
|
allDiscussions() {
|
2018-03-16 16:16:21 -04:00
|
|
|
if (this.isLoading) {
|
|
|
|
const totalNotes = parseInt(this.notesData.totalNotes, 10) || 0;
|
2018-01-04 19:18:35 -05:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
return new Array(totalNotes).fill({
|
|
|
|
isSkeletonNote: true,
|
2018-01-04 19:18:35 -05:00
|
|
|
});
|
|
|
|
}
|
2018-06-29 03:22:07 -04:00
|
|
|
|
2018-06-21 08:22:40 -04:00
|
|
|
return this.discussions;
|
2018-01-04 19:18:35 -05:00
|
|
|
},
|
2019-02-18 04:43:13 -05:00
|
|
|
canReply() {
|
2019-05-01 06:04:07 -04:00
|
|
|
return this.userCanReply && !this.commentsDisabled;
|
2019-02-18 04:43:13 -05:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
2018-06-29 03:22:07 -04:00
|
|
|
watch: {
|
|
|
|
shouldShow() {
|
|
|
|
if (!this.isNotesFetched) {
|
|
|
|
this.fetchNotes();
|
|
|
|
}
|
|
|
|
},
|
2019-02-20 09:51:06 -05:00
|
|
|
allDiscussions() {
|
|
|
|
if (this.discussonsCount) {
|
|
|
|
this.discussonsCount.textContent = this.allDiscussions.length;
|
|
|
|
}
|
|
|
|
},
|
2018-06-29 03:22:07 -04:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
created() {
|
2019-02-20 09:51:06 -05:00
|
|
|
this.discussonsCount = document.querySelector('.js-discussions-count');
|
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
this.setNotesData(this.notesData);
|
|
|
|
this.setNoteableData(this.noteableData);
|
|
|
|
this.setUserData(this.userData);
|
2018-06-21 08:22:40 -04:00
|
|
|
this.setTargetNoteHash(getLocationHash());
|
2018-06-29 03:22:07 -04:00
|
|
|
eventHub.$once('fetchNotesData', this.fetchNotes);
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
|
|
|
mounted() {
|
2018-06-29 03:22:07 -04:00
|
|
|
if (this.shouldShow) {
|
|
|
|
this.fetchNotes();
|
|
|
|
}
|
2017-07-08 05:24:13 -04:00
|
|
|
|
2018-06-29 03:22:07 -04:00
|
|
|
const { parentElement } = this.$el;
|
2018-06-21 08:22:40 -04:00
|
|
|
if (parentElement && parentElement.classList.contains('js-vue-notes-event')) {
|
2018-03-16 16:16:21 -04:00
|
|
|
parentElement.addEventListener('toggleAward', event => {
|
|
|
|
const { awardName, noteId } = event.detail;
|
2018-12-11 04:14:59 -05:00
|
|
|
this.toggleAward({ awardName, noteId });
|
2018-03-16 16:16:21 -04:00
|
|
|
});
|
|
|
|
}
|
|
|
|
},
|
2018-08-28 12:19:52 -04:00
|
|
|
updated() {
|
2018-12-07 22:12:23 -05:00
|
|
|
this.$nextTick(() => {
|
|
|
|
highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member'));
|
|
|
|
initUserPopovers(this.$el.querySelectorAll('.js-user-link'));
|
|
|
|
});
|
2018-08-28 12:19:52 -04:00
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
methods: {
|
2018-11-09 04:44:07 -05:00
|
|
|
...mapActions([
|
|
|
|
'setLoadingState',
|
|
|
|
'fetchDiscussions',
|
|
|
|
'poll',
|
|
|
|
'toggleAward',
|
|
|
|
'scrollToNoteIfNeeded',
|
|
|
|
'setNotesData',
|
|
|
|
'setNoteableData',
|
|
|
|
'setUserData',
|
|
|
|
'setLastFetchedAt',
|
|
|
|
'setTargetNoteHash',
|
|
|
|
'toggleDiscussion',
|
|
|
|
'setNotesFetchedState',
|
|
|
|
'expandDiscussion',
|
|
|
|
'startTaskList',
|
2019-02-18 04:43:13 -05:00
|
|
|
'convertToDiscussion',
|
2018-11-09 04:44:07 -05:00
|
|
|
]),
|
2018-03-16 16:16:21 -04:00
|
|
|
fetchNotes() {
|
2018-11-08 05:42:11 -05:00
|
|
|
if (this.isFetching) return null;
|
|
|
|
|
|
|
|
this.isFetching = true;
|
|
|
|
|
2018-10-23 05:49:45 -04:00
|
|
|
return this.fetchDiscussions({ path: this.getNotesDataByProp('discussionsPath') })
|
2018-06-21 08:22:40 -04:00
|
|
|
.then(() => {
|
|
|
|
this.initPolling();
|
|
|
|
})
|
2018-03-16 16:16:21 -04:00
|
|
|
.then(() => {
|
2018-10-23 05:49:45 -04:00
|
|
|
this.setLoadingState(false);
|
2018-06-29 03:22:07 -04:00
|
|
|
this.setNotesFetchedState(true);
|
2018-09-05 04:28:49 -04:00
|
|
|
eventHub.$emit('fetchedNotesData');
|
2018-11-08 05:42:11 -05:00
|
|
|
this.isFetching = false;
|
2018-03-16 16:16:21 -04:00
|
|
|
})
|
|
|
|
.then(() => this.$nextTick())
|
2018-10-25 11:51:00 -04:00
|
|
|
.then(() => this.startTaskList())
|
2018-03-16 16:16:21 -04:00
|
|
|
.then(() => this.checkLocationHash())
|
|
|
|
.catch(() => {
|
2018-10-23 05:49:45 -04:00
|
|
|
this.setLoadingState(false);
|
2018-06-29 03:22:07 -04:00
|
|
|
this.setNotesFetchedState(true);
|
2018-06-21 08:22:40 -04:00
|
|
|
Flash('Something went wrong while fetching comments. Please try again.');
|
2018-03-16 16:16:21 -04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
initPolling() {
|
|
|
|
if (this.isPollingInitialized) {
|
|
|
|
return;
|
|
|
|
}
|
2017-07-08 05:24:13 -04:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
this.setLastFetchedAt(this.getNotesDataByProp('lastFetchedAt'));
|
2017-07-26 07:02:01 -04:00
|
|
|
|
2018-03-16 16:16:21 -04:00
|
|
|
this.poll();
|
|
|
|
this.isPollingInitialized = true;
|
|
|
|
},
|
|
|
|
checkLocationHash() {
|
|
|
|
const hash = getLocationHash();
|
2018-06-21 08:22:40 -04:00
|
|
|
const noteId = hash && hash.replace(/^note_/, '');
|
2018-03-16 16:16:21 -04:00
|
|
|
|
2018-06-21 08:22:40 -04:00
|
|
|
if (noteId) {
|
2018-11-09 04:44:07 -05:00
|
|
|
const discussion = this.discussions.find(d => d.notes.some(({ id }) => id === noteId));
|
|
|
|
|
|
|
|
if (discussion) {
|
|
|
|
this.expandDiscussion({ discussionId: discussion.id });
|
|
|
|
}
|
2018-03-16 16:16:21 -04:00
|
|
|
}
|
2017-07-26 07:02:01 -04:00
|
|
|
},
|
2019-02-18 04:43:13 -05:00
|
|
|
startReplying(discussionId) {
|
|
|
|
return this.convertToDiscussion(discussionId)
|
|
|
|
.then(() => this.$nextTick())
|
|
|
|
.then(() => eventHub.$emit('startReplying', discussionId));
|
|
|
|
},
|
2018-03-16 16:16:21 -04:00
|
|
|
},
|
2018-11-09 04:44:07 -05:00
|
|
|
systemNote: constants.SYSTEM_NOTE,
|
2018-03-16 16:16:21 -04:00
|
|
|
};
|
2017-06-09 18:50:31 -04:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2018-11-16 15:07:38 -05:00
|
|
|
<div v-show="shouldShow" id="notes">
|
|
|
|
<ul id="notes-list" class="notes main-notes-list timeline">
|
2018-11-09 04:44:07 -05:00
|
|
|
<template v-for="discussion in allDiscussions">
|
|
|
|
<skeleton-loading-container v-if="discussion.isSkeletonNote" :key="discussion.id" />
|
|
|
|
<template v-else-if="discussion.isPlaceholderNote">
|
|
|
|
<placeholder-system-note
|
|
|
|
v-if="discussion.placeholderType === $options.systemNote"
|
|
|
|
:key="discussion.id"
|
|
|
|
:note="discussion.notes[0]"
|
|
|
|
/>
|
|
|
|
<placeholder-note v-else :key="discussion.id" :note="discussion.notes[0]" />
|
|
|
|
</template>
|
2019-02-14 05:07:13 -05:00
|
|
|
<template
|
|
|
|
v-else-if="discussion.individual_note && !convertedDisscussionIds.includes(discussion.id)"
|
|
|
|
>
|
2018-11-09 04:44:07 -05:00
|
|
|
<system-note
|
|
|
|
v-if="discussion.notes[0].system"
|
|
|
|
:key="discussion.id"
|
|
|
|
:note="discussion.notes[0]"
|
|
|
|
/>
|
2019-02-06 05:31:46 -05:00
|
|
|
<noteable-note
|
|
|
|
v-else
|
|
|
|
:key="discussion.id"
|
|
|
|
:note="discussion.notes[0]"
|
2019-02-18 04:43:13 -05:00
|
|
|
:show-reply-button="canReply"
|
|
|
|
@startReplying="startReplying(discussion.id)"
|
2019-02-06 05:31:46 -05:00
|
|
|
/>
|
2018-11-09 04:44:07 -05:00
|
|
|
</template>
|
|
|
|
<noteable-discussion
|
|
|
|
v-else
|
|
|
|
:key="discussion.id"
|
|
|
|
:discussion="discussion"
|
|
|
|
:render-diff-file="true"
|
2018-12-13 14:17:19 -05:00
|
|
|
:help-page-path="helpPagePath"
|
2018-11-09 04:44:07 -05:00
|
|
|
/>
|
|
|
|
</template>
|
2019-02-26 09:04:15 -05:00
|
|
|
<discussion-filter-note v-show="commentsDisabled" />
|
2017-06-13 13:01:59 -04:00
|
|
|
</ul>
|
2017-07-27 16:24:05 -04:00
|
|
|
|
2019-01-31 03:58:23 -05:00
|
|
|
<comment-form v-if="!commentsDisabled" :noteable-type="noteableType" />
|
2017-06-09 18:50:31 -04:00
|
|
|
</div>
|
|
|
|
</template>
|