Correctly resolves/unresolves discussions

This commit is contained in:
Phil Hughes 2016-07-26 13:44:51 +01:00
parent c926cdfa4f
commit 6537a4a8fe
14 changed files with 145 additions and 87 deletions

View file

@ -1,8 +1,13 @@
((w) => {
w.ResolveAll = Vue.extend({
w.ResolveAllBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: {
discussionId: String,
namespace: String,
mergeRequestId: Number,
namespacePath: String,
projectPath: String,
},
data: function() {
return {
@ -35,8 +40,15 @@
},
methods: {
resolve: function () {
ResolveService
.resolveAll(this.namespace, this.discussionId, this.allResolved);
let promise;
if (this.allResolved) {
promise = ResolveService
.unResolveAll(this.namespace, this.mergeRequestId, this.discussionId);
} else {
promise = ResolveService
.resolveAll(this.namespace, this.mergeRequestId, this.discussionId);
}
}
}
});

View file

@ -1,10 +1,14 @@
((w) => {
w.ResolveBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: {
noteId: Number,
discussionId: String,
resolved: Boolean,
namespace: String
namespacePath: String,
projectPath: String,
},
data: function () {
return {
@ -29,13 +33,26 @@
.tooltip('fixTitle');
},
resolve: function () {
let promise;
this.loading = true;
ResolveService
.resolve(this.namespace, this.discussionId, this.noteId, !this.isResolved)
.then(() => {
this.loading = false;
this.$nextTick(this.updateTooltip);
});
if (this.isResolved) {
promise = ResolveService
.unresolve(this.namespace, this.noteId);
} else {
promise = ResolveService
.resolve(this.namespace, this.noteId);
}
promise.then((response) => {
this.loading = false;
if (response.status === 200) {
CommentsStore.update(this.discussionId, this.noteId, !this.isResolved);
}
this.$nextTick(this.updateTooltip);
});
}
},
compiled: function () {

View file

@ -2,14 +2,15 @@
//= require vue-resource
//= require_directory ./stores
//= require_directory ./services
//= require_directory ./mixins
//= require_directory ./components
$(() => {
window.DiffNotesApp = new Vue({
el: '#diff-comments-app',
el: '#diff-notes-app',
components: {
'resolve-btn': ResolveBtn,
'resolve-all': ResolveAll,
'resolve-all-btn': ResolveAllBtn,
}
});

View file

@ -0,0 +1,9 @@
((w) => {
w.ButtonMixins = {
computed: {
namespace: function () {
return `${this.namespacePath}/${this.projectPath}`;
}
}
};
}(window));

View file

@ -0,0 +1,60 @@
((w) => {
class ResolveServiceClass {
constructor() {
this.noteResource = Vue.resource('notes{/noteId}/resolve');
this.discussionResource = Vue.resource('merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve');
}
setCSRF() {
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
}
resolve(namespace, noteId) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
return this.noteResource.save({ noteId }, {});
}
unresolve(namespace, noteId) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
return this.noteResource.delete({ noteId }, {});
}
resolveAll(namespace, mergeRequestId, discussionId) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
CommentsStore.loading[discussionId] = true;
return this.discussionResource.save({
mergeRequestId,
discussionId
}, {}).then((response) => {
CommentsStore.loading[discussionId] = false;
CommentsStore.updateCommentsForDiscussion(discussionId, true);
});
}
unResolveAll(namespace, mergeRequestId, discussionId) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
CommentsStore.loading[discussionId] = true;
return this.discussionResource.delete({
mergeRequestId,
discussionId
}, {}).then((response) => {
CommentsStore.loading[discussionId] = false;
CommentsStore.updateCommentsForDiscussion(discussionId, false);
});
}
}
w.ResolveService = new ResolveServiceClass();
}(window));

View file

@ -24,5 +24,25 @@
Vue.delete(this.loading, discussionId);
}
},
updateCommentsForDiscussion: function (discussionId, resolve) {
const noteIds = CommentsStore.notesForDiscussion(discussionId, resolve);
for (const noteId of noteIds) {
CommentsStore.update(discussionId, noteId, resolve);
}
},
notesForDiscussion: function (discussionId, resolve) {
let ids = [];
for (const noteId in CommentsStore.state[discussionId]) {
const resolved = CommentsStore.state[discussionId][noteId];
if (resolved !== resolve) {
ids.push(noteId);
}
}
return ids;
}
};
}(window));

View file

@ -1,64 +0,0 @@
((w) => {
class ResolveServiceClass {
constructor() {
const actions = {
resolve: {
method: 'POST',
url: 'notes{/id}/resolve',
},
all: {
method: 'POST',
url: 'notes/resolve_all',
}
};
this.resource = Vue.resource('notes{/id}', {}, actions);
}
setCSRF() {
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken();
}
resolve(namespace, discussionId, noteId, resolve) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
return this.resource
.resolve({ id: noteId }, { discussion: discussionId, resolved: resolve })
.then((response) => {
if (response.status === 200) {
CommentsStore.update(discussionId, noteId, resolve)
}
});
}
resolveAll(namespace, discussionId, allResolve) {
this.setCSRF();
Vue.http.options.root = `/${namespace}`;
let ids = []
for (const noteId in CommentsStore.state[discussionId]) {
const resolved = CommentsStore.state[discussionId][noteId];
if (resolved === allResolve) {
ids.push(noteId);
}
}
CommentsStore.loading[discussionId] = true;
return this.resource
.all({}, { ids: ids, discussion: discussionId, resolved: !allResolve })
.then((response) => {
if (response.status === 200) {
for (const noteId in ids) {
CommentsStore.update(discussionId, noteId, !allResolve);
}
}
CommentsStore.loading[discussionId] = false;
});
}
}
w.ResolveService = new ResolveServiceClass();
}(window));

View file

@ -120,8 +120,8 @@
return function(data) {
$('#diffs').html(data.html);
if ($('resolve-btn, resolve-all').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all').each(function () {
if ($('resolve-btn, resolve-all-btn').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all-btn').each(function () {
DiffNotesApp.$compile($(this).get(0))
});
}

View file

@ -300,8 +300,8 @@
discussionContainer.append(note_html);
}
if ($('resolve-btn, resolve-all').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all').each(function () {
if ($('resolve-btn, resolve-all-btn').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all-btn').each(function () {
DiffNotesApp.$compile($(this).get(0))
});
}

View file

@ -1,6 +1,8 @@
- if discussion.can_resolve?(current_user)
%resolve-all{ ":namespace" => "'#{discussion.project.namespace.path}/#{discussion.project.path}'",
%resolve-all-btn{ ":namespace-path" => "'#{discussion.project.namespace.path}'",
":project-path" => "'#{discussion.project.path}'",
":discussion-id" => "'#{discussion.id}'",
":merge-request-id" => "#{discussion.first_note.noteable.iid}",
"inline-template" => true,
"v-cloak" => true }
%button.btn.btn-default{ type: "button", "@click" => "resolve", ":disabled" => "loading" }

View file

@ -2,7 +2,7 @@
- page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do
= page_specific_javascript_tag('line_comments/line_comments_bundle.js')
= page_specific_javascript_tag('diff_notes/diff_notes_bundle.js')
- if diff_view == 'parallel'
- fluid_layout true
@ -71,7 +71,7 @@
Changes
%span.badge= @merge_request.diff_size
.tab-content#diff-comments-app
.tab-content#diff-notes-app
#notes.notes.tab-pane.voting_notes
.content-block.content-block-small.oneline-block
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true

View file

@ -24,7 +24,8 @@
- if note.resolvable?
- if can?(current_user, :resolve_note, note)
%resolve-btn{ ":namespace" => "'#{note.project.namespace.path}/#{note.project.path}'",
%resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'",
":project-path" => "'#{note.project.path}'",
":discussion-id" => "'#{note.discussion_id}'",
":note-id" => note.id,
":resolved" => note.resolved?,

View file

@ -85,7 +85,7 @@ module Gitlab
config.assets.precompile << "users/users_bundle.js"
config.assets.precompile << "network/network_bundle.js"
config.assets.precompile << "profile/profile_bundle.js"
config.assets.precompile << "line_comments/line_comments_bundle.js"
config.assets.precompile << "diff_notes/diff_notes_bundle.js"
config.assets.precompile << "lib/utils/*.js"
config.assets.precompile << "lib/*.js"
config.assets.precompile << "u2f.js"