Commit 6537a4a8 authored by Phil Hughes's avatar Phil Hughes

Correctly resolves/unresolves discussions

parent c926cdfa
((w) => { ((w) => {
w.ResolveAll = Vue.extend({ w.ResolveAllBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: { props: {
discussionId: String, discussionId: String,
namespace: String, mergeRequestId: Number,
namespacePath: String,
projectPath: String,
}, },
data: function() { data: function() {
return { return {
...@@ -35,8 +40,15 @@ ...@@ -35,8 +40,15 @@
}, },
methods: { methods: {
resolve: function () { resolve: function () {
ResolveService let promise;
.resolveAll(this.namespace, this.discussionId, this.allResolved);
if (this.allResolved) {
promise = ResolveService
.unResolveAll(this.namespace, this.mergeRequestId, this.discussionId);
} else {
promise = ResolveService
.resolveAll(this.namespace, this.mergeRequestId, this.discussionId);
}
} }
} }
}); });
......
((w) => { ((w) => {
w.ResolveBtn = Vue.extend({ w.ResolveBtn = Vue.extend({
mixins: [
ButtonMixins
],
props: { props: {
noteId: Number, noteId: Number,
discussionId: String, discussionId: String,
resolved: Boolean, resolved: Boolean,
namespace: String namespacePath: String,
projectPath: String,
}, },
data: function () { data: function () {
return { return {
...@@ -29,13 +33,26 @@ ...@@ -29,13 +33,26 @@
.tooltip('fixTitle'); .tooltip('fixTitle');
}, },
resolve: function () { resolve: function () {
let promise;
this.loading = true; this.loading = true;
ResolveService
.resolve(this.namespace, this.discussionId, this.noteId, !this.isResolved) if (this.isResolved) {
.then(() => { promise = ResolveService
this.loading = false; .unresolve(this.namespace, this.noteId);
this.$nextTick(this.updateTooltip); } 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 () { compiled: function () {
......
...@@ -2,14 +2,15 @@ ...@@ -2,14 +2,15 @@
//= require vue-resource //= require vue-resource
//= require_directory ./stores //= require_directory ./stores
//= require_directory ./services //= require_directory ./services
//= require_directory ./mixins
//= require_directory ./components //= require_directory ./components
$(() => { $(() => {
window.DiffNotesApp = new Vue({ window.DiffNotesApp = new Vue({
el: '#diff-comments-app', el: '#diff-notes-app',
components: { components: {
'resolve-btn': ResolveBtn, 'resolve-btn': ResolveBtn,
'resolve-all': ResolveAll, 'resolve-all-btn': ResolveAllBtn,
} }
}); });
......
((w) => {
w.ButtonMixins = {
computed: {
namespace: function () {
return `${this.namespacePath}/${this.projectPath}`;
}
}
};
}(window));
((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));
...@@ -24,5 +24,25 @@ ...@@ -24,5 +24,25 @@
Vue.delete(this.loading, discussionId); 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)); }(window));
((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));
...@@ -120,8 +120,8 @@ ...@@ -120,8 +120,8 @@
return function(data) { return function(data) {
$('#diffs').html(data.html); $('#diffs').html(data.html);
if ($('resolve-btn, resolve-all').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) { if ($('resolve-btn, resolve-all-btn').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all').each(function () { $('resolve-btn, resolve-all-btn').each(function () {
DiffNotesApp.$compile($(this).get(0)) DiffNotesApp.$compile($(this).get(0))
}); });
} }
......
...@@ -300,8 +300,8 @@ ...@@ -300,8 +300,8 @@
discussionContainer.append(note_html); discussionContainer.append(note_html);
} }
if ($('resolve-btn, resolve-all').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) { if ($('resolve-btn, resolve-all-btn').length && (typeof DiffNotesApp !== "undefined" && DiffNotesApp !== null)) {
$('resolve-btn, resolve-all').each(function () { $('resolve-btn, resolve-all-btn').each(function () {
DiffNotesApp.$compile($(this).get(0)) DiffNotesApp.$compile($(this).get(0))
}); });
} }
......
- if discussion.can_resolve?(current_user) - 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}'", ":discussion-id" => "'#{discussion.id}'",
":merge-request-id" => "#{discussion.first_note.noteable.iid}",
"inline-template" => true, "inline-template" => true,
"v-cloak" => true } "v-cloak" => true }
%button.btn.btn-default{ type: "button", "@click" => "resolve", ":disabled" => "loading" } %button.btn.btn-default{ type: "button", "@click" => "resolve", ":disabled" => "loading" }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- page_description @merge_request.description - page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes - page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do - 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' - if diff_view == 'parallel'
- fluid_layout true - fluid_layout true
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
Changes Changes
%span.badge= @merge_request.diff_size %span.badge= @merge_request.diff_size
.tab-content#diff-comments-app .tab-content#diff-notes-app
#notes.notes.tab-pane.voting_notes #notes.notes.tab-pane.voting_notes
.content-block.content-block-small.oneline-block .content-block.content-block-small.oneline-block
= render 'award_emoji/awards_block', awardable: @merge_request, inline: true = render 'award_emoji/awards_block', awardable: @merge_request, inline: true
......
...@@ -24,13 +24,14 @@ ...@@ -24,13 +24,14 @@
- if note.resolvable? - if note.resolvable?
- if can?(current_user, :resolve_note, note) - 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}'", ":discussion-id" => "'#{note.discussion_id}'",
":note-id" => note.id, ":note-id" => note.id,
":resolved" => note.resolved?, ":resolved" => note.resolved?,
"inline-template" => true, "inline-template" => true,
"v-ref:note_#{note.id}" => true } "v-ref:note_#{note.id}" => true }
.note-action-button .note-action-button
= icon("spin spinner", "v-show" => "loading") = icon("spin spinner", "v-show" => "loading")
%button.line-resolve-btn{ type: "button", %button.line-resolve-btn{ type: "button",
......
...@@ -85,7 +85,7 @@ module Gitlab ...@@ -85,7 +85,7 @@ module Gitlab
config.assets.precompile << "users/users_bundle.js" config.assets.precompile << "users/users_bundle.js"
config.assets.precompile << "network/network_bundle.js" config.assets.precompile << "network/network_bundle.js"
config.assets.precompile << "profile/profile_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/utils/*.js"
config.assets.precompile << "lib/*.js" config.assets.precompile << "lib/*.js"
config.assets.precompile << "u2f.js" config.assets.precompile << "u2f.js"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment