notes_app.vue 5.79 KB
Newer Older
1
<script>
Fatih Acet's avatar
Fatih Acet committed
2 3 4 5
import { mapGetters, mapActions } from 'vuex';
import { getLocationHash } from '../../lib/utils/url_utility';
import Flash from '../../flash';
import * as constants from '../constants';
6
import eventHub from '../event_hub';
Fatih Acet's avatar
Fatih Acet committed
7 8 9 10 11 12 13
import noteableNote from './noteable_note.vue';
import noteableDiscussion from './noteable_discussion.vue';
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';
14
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
15

Fatih Acet's avatar
Fatih Acet committed
16 17 18 19 20 21 22 23 24 25 26 27 28 29
export default {
  name: 'NotesApp',
  components: {
    noteableNote,
    noteableDiscussion,
    systemNote,
    commentForm,
    placeholderNote,
    placeholderSystemNote,
  },
  props: {
    noteableData: {
      type: Object,
      required: true,
Filipa Lacerda's avatar
Filipa Lacerda committed
30
    },
Fatih Acet's avatar
Fatih Acet committed
31 32 33
    notesData: {
      type: Object,
      required: true,
34
    },
Fatih Acet's avatar
Fatih Acet committed
35 36 37 38
    userData: {
      type: Object,
      required: false,
      default: () => ({}),
39
    },
Felipe Artur's avatar
Felipe Artur committed
40 41 42 43 44
    shouldShow: {
      type: Boolean,
      required: false,
      default: true,
    },
45 46 47 48 49
    markdownVersion: {
      type: Number,
      required: false,
      default: 0,
    },
Fatih Acet's avatar
Fatih Acet committed
50 51 52
  },
  data() {
    return {
53
      currentFilter: null,
Fatih Acet's avatar
Fatih Acet committed
54 55 56
    };
  },
  computed: {
57 58 59 60 61 62
    ...mapGetters([
      'isNotesFetched',
      'discussions',
      'getNotesDataByProp',
      'discussionCount',
      'isLoading',
63
      'commentsDisabled',
64
    ]),
Fatih Acet's avatar
Fatih Acet committed
65
    noteableType() {
66
      return this.noteableData.noteableType;
Filipa Lacerda's avatar
Filipa Lacerda committed
67
    },
Felipe Artur's avatar
Felipe Artur committed
68
    allDiscussions() {
Fatih Acet's avatar
Fatih Acet committed
69 70
      if (this.isLoading) {
        const totalNotes = parseInt(this.notesData.totalNotes, 10) || 0;
Filipa Lacerda's avatar
Filipa Lacerda committed
71

Fatih Acet's avatar
Fatih Acet committed
72 73
        return new Array(totalNotes).fill({
          isSkeletonNote: true,
Filipa Lacerda's avatar
Filipa Lacerda committed
74 75
        });
      }
76

Felipe Artur's avatar
Felipe Artur committed
77
      return this.discussions;
Filipa Lacerda's avatar
Filipa Lacerda committed
78
    },
Fatih Acet's avatar
Fatih Acet committed
79
  },
80 81 82 83 84 85 86
  watch: {
    shouldShow() {
      if (!this.isNotesFetched) {
        this.fetchNotes();
      }
    },
  },
Fatih Acet's avatar
Fatih Acet committed
87 88 89 90
  created() {
    this.setNotesData(this.notesData);
    this.setNoteableData(this.noteableData);
    this.setUserData(this.userData);
Felipe Artur's avatar
Felipe Artur committed
91
    this.setTargetNoteHash(getLocationHash());
92
    eventHub.$once('fetchNotesData', this.fetchNotes);
Fatih Acet's avatar
Fatih Acet committed
93 94
  },
  mounted() {
95 96 97
    if (this.shouldShow) {
      this.fetchNotes();
    }
98

99
    const { parentElement } = this.$el;
Felipe Artur's avatar
Felipe Artur committed
100
    if (parentElement && parentElement.classList.contains('js-vue-notes-event')) {
Fatih Acet's avatar
Fatih Acet committed
101 102 103 104 105 106
      parentElement.addEventListener('toggleAward', event => {
        const { awardName, noteId } = event.detail;
        this.actionToggleAward({ awardName, noteId });
      });
    }
  },
107 108 109
  updated() {
    this.$nextTick(() => highlightCurrentUser(this.$el.querySelectorAll('.gfm-project_member')));
  },
Fatih Acet's avatar
Fatih Acet committed
110 111
  methods: {
    ...mapActions({
112
      setLoadingState: 'setLoadingState',
Felipe Artur's avatar
Felipe Artur committed
113
      fetchDiscussions: 'fetchDiscussions',
Fatih Acet's avatar
Fatih Acet committed
114 115 116 117 118 119 120 121
      poll: 'poll',
      actionToggleAward: 'toggleAward',
      scrollToNoteIfNeeded: 'scrollToNoteIfNeeded',
      setNotesData: 'setNotesData',
      setNoteableData: 'setNoteableData',
      setUserData: 'setUserData',
      setLastFetchedAt: 'setLastFetchedAt',
      setTargetNoteHash: 'setTargetNoteHash',
Felipe Artur's avatar
Felipe Artur committed
122
      toggleDiscussion: 'toggleDiscussion',
123
      setNotesFetchedState: 'setNotesFetchedState',
Fatih Acet's avatar
Fatih Acet committed
124
    }),
Felipe Artur's avatar
Felipe Artur committed
125 126
    getComponentName(discussion) {
      if (discussion.isSkeletonNote) {
Fatih Acet's avatar
Fatih Acet committed
127 128
        return skeletonLoadingContainer;
      }
Felipe Artur's avatar
Felipe Artur committed
129 130
      if (discussion.isPlaceholderNote) {
        if (discussion.placeholderType === constants.SYSTEM_NOTE) {
Fatih Acet's avatar
Fatih Acet committed
131
          return placeholderSystemNote;
132
        }
Fatih Acet's avatar
Fatih Acet committed
133
        return placeholderNote;
Felipe Artur's avatar
Felipe Artur committed
134 135
      } else if (discussion.individual_note) {
        return discussion.notes[0].system ? systemNote : noteableNote;
Fatih Acet's avatar
Fatih Acet committed
136
      }
137

Fatih Acet's avatar
Fatih Acet committed
138 139
      return noteableDiscussion;
    },
Felipe Artur's avatar
Felipe Artur committed
140 141
    getComponentData(discussion) {
      return discussion.individual_note ? { note: discussion.notes[0] } : { discussion };
Fatih Acet's avatar
Fatih Acet committed
142 143
    },
    fetchNotes() {
144
      return this.fetchDiscussions({ path: this.getNotesDataByProp('discussionsPath') })
Felipe Artur's avatar
Felipe Artur committed
145 146 147
        .then(() => {
          this.initPolling();
        })
Fatih Acet's avatar
Fatih Acet committed
148
        .then(() => {
149
          this.setLoadingState(false);
150
          this.setNotesFetchedState(true);
151
          eventHub.$emit('fetchedNotesData');
Fatih Acet's avatar
Fatih Acet committed
152 153 154 155
        })
        .then(() => this.$nextTick())
        .then(() => this.checkLocationHash())
        .catch(() => {
156
          this.setLoadingState(false);
157
          this.setNotesFetchedState(true);
Felipe Artur's avatar
Felipe Artur committed
158
          Flash('Something went wrong while fetching comments. Please try again.');
Fatih Acet's avatar
Fatih Acet committed
159 160 161 162 163 164
        });
    },
    initPolling() {
      if (this.isPollingInitialized) {
        return;
      }
165

Fatih Acet's avatar
Fatih Acet committed
166
      this.setLastFetchedAt(this.getNotesDataByProp('lastFetchedAt'));
167

Fatih Acet's avatar
Fatih Acet committed
168 169 170 171 172
      this.poll();
      this.isPollingInitialized = true;
    },
    checkLocationHash() {
      const hash = getLocationHash();
Felipe Artur's avatar
Felipe Artur committed
173
      const noteId = hash && hash.replace(/^note_/, '');
Fatih Acet's avatar
Fatih Acet committed
174

Felipe Artur's avatar
Felipe Artur committed
175 176 177 178 179 180 181 182 183 184 185
      if (noteId) {
        this.discussions.forEach(discussion => {
          if (discussion.notes) {
            discussion.notes.forEach(note => {
              if (`${note.id}` === `${noteId}`) {
                // FIXME: this modifies the store state without using a mutation/action
                Object.assign(discussion, { expanded: true });
              }
            });
          }
        });
Fatih Acet's avatar
Fatih Acet committed
186
      }
187
    },
Fatih Acet's avatar
Fatih Acet committed
188 189
  },
};
190 191 192
</script>

<template>
Felipe Artur's avatar
Felipe Artur committed
193
  <div
194
    v-show="shouldShow"
195 196
    id="notes"
  >
197
    <ul
198
      id="notes-list"
199 200
      class="notes main-notes-list timeline"
    >
201
      <component
Felipe Artur's avatar
Felipe Artur committed
202
        :is="getComponentName(discussion)"
203
        v-for="discussion in allDiscussions"
Felipe Artur's avatar
Felipe Artur committed
204
        :key="discussion.id"
205
        v-bind="getComponentData(discussion)"
Filipa Lacerda's avatar
Filipa Lacerda committed
206
      />
207
    </ul>
208

209
    <comment-form
210
      v-if="!commentsDisabled"
211
      :noteable-type="noteableType"
212
      :markdown-version="markdownVersion"
213
    />
214 215
  </div>
</template>