diff --git a/app/assets/javascripts/line_comments/components/resolve_all.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_all_btn.js.es6
similarity index 65%
rename from app/assets/javascripts/line_comments/components/resolve_all.js.es6
rename to app/assets/javascripts/diff_notes/components/resolve_all_btn.js.es6
index a1564a680960e83b2dbe30fc77b9f7af07358537..4c56386ad6651ba5fd80b2a7f4a052ecb14fcdb9 100644
--- a/app/assets/javascripts/line_comments/components/resolve_all.js.es6
+++ b/app/assets/javascripts/diff_notes/components/resolve_all_btn.js.es6
@@ -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);
+        }
       }
     }
   });
diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
similarity index 63%
rename from app/assets/javascripts/line_comments/components/resolve_btn.js.es6
rename to app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
index fa0e727c6d48ff5b18f093359ceccde7443bd351..b60b8424d412c5daebd54d12d202d634284a8b88 100644
--- a/app/assets/javascripts/line_comments/components/resolve_btn.js.es6
+++ b/app/assets/javascripts/diff_notes/components/resolve_btn.js.es6
@@ -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 () {
diff --git a/app/assets/javascripts/line_comments/components/resolve_count.js.es6 b/app/assets/javascripts/diff_notes/components/resolve_count.js.es6
similarity index 100%
rename from app/assets/javascripts/line_comments/components/resolve_count.js.es6
rename to app/assets/javascripts/diff_notes/components/resolve_count.js.es6
diff --git a/app/assets/javascripts/line_comments/line_comments_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
similarity index 78%
rename from app/assets/javascripts/line_comments/line_comments_bundle.js.es6
rename to app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
index 6866e6b6f54970b9676ec7d6544fe55d5ff460d5..0605ad0e75011022ca49cd9bf8ce66475d7ec75d 100644
--- a/app/assets/javascripts/line_comments/line_comments_bundle.js.es6
+++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6
@@ -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,
     }
   });
 
diff --git a/app/assets/javascripts/diff_notes/mixins/namespace.js.es6 b/app/assets/javascripts/diff_notes/mixins/namespace.js.es6
new file mode 100644
index 0000000000000000000000000000000000000000..5215e7c6be7ce8fceceac099860bcba3bdd6c25b
--- /dev/null
+++ b/app/assets/javascripts/diff_notes/mixins/namespace.js.es6
@@ -0,0 +1,9 @@
+((w) => {
+  w.ButtonMixins = {
+    computed: {
+      namespace: function () {
+        return `${this.namespacePath}/${this.projectPath}`;
+      }
+    }
+  };
+}(window));
diff --git a/app/assets/javascripts/diff_notes/services/resolve.js.es6 b/app/assets/javascripts/diff_notes/services/resolve.js.es6
new file mode 100644
index 0000000000000000000000000000000000000000..052f3c5f721f8ff2d844619482fb508595b7c9e7
--- /dev/null
+++ b/app/assets/javascripts/diff_notes/services/resolve.js.es6
@@ -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));
diff --git a/app/assets/javascripts/line_comments/stores/comments.js.es6 b/app/assets/javascripts/diff_notes/stores/comments.js.es6
similarity index 58%
rename from app/assets/javascripts/line_comments/stores/comments.js.es6
rename to app/assets/javascripts/diff_notes/stores/comments.js.es6
index 709361372acc311bdc1d64f3ba5feda212c6dbc1..cd9810239449defbf8d2161333e944e32f3bd0bf 100644
--- a/app/assets/javascripts/line_comments/stores/comments.js.es6
+++ b/app/assets/javascripts/diff_notes/stores/comments.js.es6
@@ -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));
diff --git a/app/assets/javascripts/line_comments/services/resolve.js.es6 b/app/assets/javascripts/line_comments/services/resolve.js.es6
deleted file mode 100644
index e2be311cb15e800a8b20c1863d846c783966d496..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/line_comments/services/resolve.js.es6
+++ /dev/null
@@ -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));
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 61d05932b57c037c324305fbb83050c2a29263bb..332288dcf8e2b727e21aed7c3ba6cfb6164761a1 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -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))
               });
             }
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index bb20c143a4dc4ea48b86395fdd427880e7b44bbc..b5fc21e331bac6180961ac104c9e18129e56a6b0 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -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))
         });
       }
diff --git a/app/views/discussions/_resolve_all.html.haml b/app/views/discussions/_resolve_all.html.haml
index 8b5655af2a11b494c9611de0688f2337ffb6fbed..6c4e37be8547c5a63c33b6322de5aa252f0c5cfe 100644
--- a/app/views/discussions/_resolve_all.html.haml
+++ b/app/views/discussions/_resolve_all.html.haml
@@ -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" }
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 14092c38a9554bbbe65490f2e93a2d896b858fd1..cd71e1d6a38ddca3880212d8f91519a494ad73e0 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -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
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 0fce8d06b5f77af37c640ac47b6f9aef1beb432f..c90be872ff4226468f4175b909bbd8137f5a9391 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -24,13 +24,14 @@
 
             - 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?,
                     "inline-template" => true,
                     "v-ref:note_#{note.id}" => true }
-                    
+
                   .note-action-button
                     = icon("spin spinner", "v-show" => "loading")
                     %button.line-resolve-btn{ type: "button",
diff --git a/config/application.rb b/config/application.rb
index 5a4b7fa3ee4af3fe124f9552f571a42ae96ae3c2..1646461939d66684d4f5d1b3c0f6e112038b1933 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -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"