IssueDiscussionsRefactor: Implement polling mechanism.

This commit is contained in:
Fatih Acet 2017-06-29 18:59:22 +03:00
parent 17d67a989b
commit 15f3362d34
5 changed files with 71 additions and 8 deletions

View File

@ -133,13 +133,13 @@ export default {
ref="textarea"
slot="textarea"
placeholder="Write a comment or drag your files here..."
@keydown.meta.enter="handleSave">
@keydown.meta.enter="handleSave()">
</textarea>
</markdown-field>
<div class="note-form-actions clearfix">
<div class="pull-left btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown">
<input
@click="handleSave"
@click="handleSave()"
:disabled="!note.length"
:value="commentButtonTitle"
class="btn btn-nr btn-create comment-btn js-comment-button js-comment-submit-button"

View File

@ -39,14 +39,27 @@ export default {
},
},
mounted() {
const path = this.$el.parentNode.dataset.discussionsPath;
this.$store.dispatch('fetchNotes', path)
const { discussionsPath, notesPath, lastFetchedAt } = this.$el.parentNode.dataset;
this.$store.dispatch('fetchNotes', discussionsPath)
.then(() => {
this.isLoading = false;
})
.catch(() => {
new Flash('Something went wrong while fetching issue comments. Please try again.'); // eslint-disable-line
});
const options = {
endpoint: `${notesPath}?full_data=1`,
lastFetchedAt,
};
// FIXME: @fatihacet Implement real polling mechanism
setInterval(() => {
this.$store.dispatch('poll', options)
.then((res) => {
options.lastFetchedAt = res.last_fetched_at;
});
}, 6000);
},
};
</script>

View File

@ -19,4 +19,13 @@ export default {
createNewNote(endpoint, data) {
return Vue.http.post(endpoint, data, { emulateJSON: true });
},
poll(endpoint, lastFetchedAt) {
const options = {
headers: {
'X-Last-Fetched-At': lastFetchedAt,
}
};
return Vue.http.get(endpoint, options);
},
};

View File

@ -15,7 +15,7 @@ const getters = {
};
const mutations = {
setNotes(storeState, notes) {
setInitialNotes(storeState, notes) {
storeState.notes = notes;
},
toggleDiscussion(storeState, { discussionId }) {
@ -40,7 +40,9 @@ const mutations = {
addNewReplyToDiscussion(storeState, note) {
const noteObj = findNoteObjectById(storeState.notes, note.discussion_id);
noteObj.notes.push(note);
if (noteObj) {
noteObj.notes.push(note);
}
},
updateNote(storeState, note) {
const noteObj = findNoteObjectById(storeState.notes, note.discussion_id);
@ -72,7 +74,7 @@ const actions = {
.fetchNotes(path)
.then(res => res.json())
.then((res) => {
context.commit('setNotes', res);
context.commit('setInitialNotes', res);
});
},
deleteNote(context, note) {
@ -114,6 +116,45 @@ const actions = {
return res;
});
},
poll(context, data) {
const { endpoint, lastFetchedAt } = data;
return service
.poll(endpoint, lastFetchedAt)
.then(res => res.json())
.then((res) => {
if (res.notes.length) {
const notesById = {};
// Simple lookup object to check whether we have a discussion id already in our store
context.state.notes.forEach((note) => {
note.notes.forEach((n) => {
notesById[n.id] = true;
});
});
res.notes.forEach((note) => {
if (notesById[note.id]) {
context.commit('updateNote', note);
} else {
if (note.type === 'DiscussionNote') {
const discussion = findNoteObjectById(context.state.notes, note.discussion_id);
if (discussion) {
context.commit('addNewReplyToDiscussion', note);
} else {
context.commit('addNewNote', note);
}
} else {
context.commit('addNewNote', note);
}
}
});
}
return res;
});
},
};
export default {

View File

@ -3,7 +3,7 @@
= link_to 'Reopen issue', issue_path(@issue, issue: {state_event: :reopen}, format: 'json'), data: {original_text: "Reopen issue", alternative_text: "Comment & reopen issue"}, class: "btn btn-nr btn-reopen btn-comment js-note-target-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
= link_to 'Close issue', issue_path(@issue, issue: {state_event: :close}, format: 'json'), data: {original_text: "Close issue", alternative_text: "Comment & close issue"}, class: "btn btn-nr btn-close btn-comment js-note-target-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
%section{ data: { discussions_path: discussions_namespace_project_issue_path(@project.namespace, @project, @issue, format: :json), new_session_path: new_session_path(:user, redirect_to_referer: 'yes') } }
%section{ data: { discussions_path: discussions_namespace_project_issue_path(@project.namespace, @project, @issue, format: :json), new_session_path: new_session_path(:user, redirect_to_referer: 'yes'), notes_path: notes_url, last_fetched_at: Time.now.to_i } }
#js-notes
- content_for :page_specific_javascripts do
= webpack_bundle_tag 'common_vue'