diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index a3185f876408aaf2a85d4c69d9886584c509857e..61edcf8fdd7617f3b637ddced43f91060987cf80 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -74,6 +74,7 @@ class Dispatcher
       when 'projects:show'
         shortcut_handler = new ShortcutsNavigation()
 
+        new NotificationsForm()
         new TreeView() if $('#tree-slider').length
       when 'groups:activity'
         new Activities()
diff --git a/app/assets/javascripts/notifications_form.js.coffee b/app/assets/javascripts/notifications_form.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..cfe8e133b66557cc3b3e35132a826599b6e19d07
--- /dev/null
+++ b/app/assets/javascripts/notifications_form.js.coffee
@@ -0,0 +1,49 @@
+class @NotificationsForm
+  constructor: ->
+    @form = $('.custom-notifications-form')
+
+    @removeEventListeners()
+    @initEventListeners()
+
+  removeEventListeners: ->
+    $(document).off 'change', '.js-custom-notification-event'
+
+  initEventListeners: ->
+    $(document).on 'change', '.js-custom-notification-event', @toggleCheckbox
+
+  toggleCheckbox: (e) =>
+    $checkbox = $(e.currentTarget)
+    $parent = $checkbox.closest('.checkbox')
+
+    @saveEvent($checkbox, $parent)
+
+  showCheckboxLoadingSpinner: ($parent) ->
+    $parent
+      .addClass 'is-loading'
+      .find '.custom-notification-event-loading'
+      .removeClass 'fa-check'
+      .addClass 'fa-spin fa-spinner'
+      .removeClass 'is-done'
+
+  saveEvent: ($checkbox, $parent) ->
+    $.ajax(
+      url: @form.attr('action')
+      method: 'patch'
+      dataType: 'json'
+      data: @form.serialize()
+      beforeSend: =>
+        @showCheckboxLoadingSpinner($parent)
+    ).done (data) ->
+      $checkbox.enable()
+
+      if data.saved
+        $parent
+          .find '.custom-notification-event-loading'
+          .toggleClass 'fa-spin fa-spinner fa-check is-done'
+
+        setTimeout(->
+          $parent
+            .removeClass 'is-loading'
+            .find '.custom-notification-event-loading'
+            .toggleClass 'fa-spin fa-spinner fa-check is-done'
+        , 2000)
diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee
index 07be85a32a5cfa43b813626512de3ab8646cf77c..236f0899147b7156caba7baa6da3ce582d94c5a3 100644
--- a/app/assets/javascripts/project.js.coffee
+++ b/app/assets/javascripts/project.js.coffee
@@ -34,21 +34,26 @@ class @Project
       $(@).parents('.no-password-message').remove()
       e.preventDefault()
 
-    $('.update-notification').on 'click', (e) ->
-      e.preventDefault()
-      notification_level = $(@).data 'notification-level'
-      label = $(@).data 'notification-title'
-      $('#notification_setting_level').val(notification_level)
-      $('#notification-form').submit()
-      $('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>")
-      $(@).parents('ul').find('li.active').removeClass 'active'
-      $(@).parent().addClass 'active'
-
-    $('#notification-form').on 'ajax:success', (e, data) ->
-      if data.saved
-        new Flash("Notification settings saved", "notice")
-      else
-        new Flash("Failed to save new settings", "alert")
+    $(document)
+      .off 'click', '.update-notification'
+      .on 'click', '.update-notification', (e) ->
+        e.preventDefault()
+        notificationLevel = $(@).data 'notification-level'
+        label = $(@).data 'notification-title'
+        $('.js-notification-loading').toggleClass 'fa-bell fa-spin fa-spinner'
+        $('#notification_setting_level').val(notificationLevel)
+        $('#notification-form').submit()
+
+    $(document)
+      .off 'ajax:success', '#notification-form'
+      .on 'ajax:success', '#notification-form', (e, data) ->
+        if data.saved
+          new Flash('Notification settings saved', 'notice')
+          $('.js-notification-toggle-btns')
+            .closest('.notification-dropdown')
+            .replaceWith(data.html)
+        else
+          new Flash('Failed to save new settings', 'alert')
 
 
     @projectSelectDropdown()
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index edef336481d46e91a89da58f635e8651cc0dc0a0..448ece1bff779e71bc2a6fbabd25020d157dfb71 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -125,11 +125,6 @@
       }
     }
 
-    .btn-group:not(:first-child):not(:last-child) > .btn {
-      border-top-right-radius: 3px;
-      border-bottom-right-radius: 3px;
-    }
-
     form {
       margin-left: 10px;
     }
@@ -594,3 +589,20 @@ pre.light-well {
     }
   }
 }
+
+.custom-notifications-form {
+  .is-loading {
+    .custom-notification-event-loading {
+      display: inline-block;
+    }
+  }
+}
+
+.custom-notification-event-loading {
+  display: none;
+  margin-left: 5px;
+
+  &.is-done {
+    color: $gl-text-green;
+  }
+}
diff --git a/app/controllers/projects/notification_settings_controller.rb b/app/controllers/projects/notification_settings_controller.rb
index 7d81cc03c73f6a91bc322ca5221654ed163a03cb..13b38501ae4c117997786f10633ed446e6e7c476 100644
--- a/app/controllers/projects/notification_settings_controller.rb
+++ b/app/controllers/projects/notification_settings_controller.rb
@@ -2,10 +2,24 @@ class Projects::NotificationSettingsController < Projects::ApplicationController
   before_action :authenticate_user!
 
   def update
-    notification_setting = current_user.notification_settings_for(project)
-    saved = notification_setting.update_attributes(notification_setting_params)
+    @notification_setting = current_user.notification_settings_for(project)
 
-    render json: { saved: saved }
+    if params[:custom_events].nil?
+      saved = @notification_setting.update_attributes(notification_setting_params)
+    else
+      events = params[:events] || {}
+
+      NotificationSetting::EMAIL_EVENTS.each do |event|
+        @notification_setting.events[event] = events[event]
+      end
+
+      saved = @notification_setting.save
+    end
+
+    render json: {
+      html: view_to_html_string("projects/buttons/_notifications", locals: { project: @project, notification_setting: @notification_setting }),
+      saved: saved,
+    }
   end
 
   private
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 57c3d1b0a65bb08284fcde02c4255721c2afb5ec..0ee1c83cd11356f2259509de8f66276045ab73b9 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -29,9 +29,10 @@
           .project-clone-holder
             = render "shared/clone_panel"
 
-    .project-repo-buttons.btn-group.project-right-buttons
-      = render "projects/buttons/download"
-      = render 'projects/buttons/dropdown'
+    .project-repo-buttons.project-right-buttons
+      .btn-group
+        = render "projects/buttons/download"
+        = render 'projects/buttons/dropdown'
       = render 'projects/buttons/notifications'
 
 :javascript
diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml
index 1d05da50581fdd72fd4a0b6e4a4a89e571ff4787..47a12e6f8cb19753fd6e9e811e01ad5492aaf615 100644
--- a/app/views/projects/buttons/_notifications.html.haml
+++ b/app/views/projects/buttons/_notifications.html.haml
@@ -1,11 +1,21 @@
 - if @notification_setting
-  = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
-    = f.hidden_field :level
-    .dropdown
-      %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
-        = icon('bell')
-        = notification_title(@notification_setting.level)
-        = icon('caret-down')
-      %ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
-        - NotificationSetting.levels.each do |level|
-          = notification_list_item(level.first, @notification_setting)
+  .dropdown.notification-dropdown.pull-right
+    = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: "inline", id: "notification-form" } do |f|
+      = f.hidden_field :level
+      .js-notification-toggle-btns
+        - if @notification_setting.level != "custom"
+          %button.dropdown-new.btn.btn-default.notifications-btn#notifications-button{ type: "button", data: { toggle: "dropdown", target: ".notification-dropdown" } }
+            = icon("bell", class: "js-notification-loading")
+            = notification_title(@notification_setting.level)
+            = icon("caret-down")
+        - else
+          .btn-group
+            %button.dropdown-new.btn.btn-default.notifications-btn#notifications-button{ type: "button", data: { toggle: "modal", target: "#custom-notifications-modal" } }
+              = icon("bell", class: "js-notification-loading")
+              = notification_title(@notification_setting.level)
+            %button.btn.btn-danger.dropdown-toggle{ data: { toggle: "dropdown", target: ".notification-dropdown" } }
+              %span.caret
+              .sr-only Toggle dropdown
+      = render "shared/projects/notification_dropdown"
+  = content_for :scripts_body do
+    = render "shared/projects/custom_notifications"
diff --git a/app/views/shared/projects/_custom_notifications.html.haml b/app/views/shared/projects/_custom_notifications.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..8569c523ef47254356420c963288e5acf99fd523
--- /dev/null
+++ b/app/views/shared/projects/_custom_notifications.html.haml
@@ -0,0 +1,27 @@
+#custom-notifications-modal.modal.fade{ tabindex: "-1", role: "dialog", aria: { labelledby: "custom-notifications-title" } }
+  .modal-dialog
+    .modal-content
+      .modal-header
+        %button.close{ type: "button", data: { dismiss: "modal" }, aria: { label: "close" } }
+          %span{ aria: { hidden: "true" } } ×
+        %h4#custom-notifications-title.modal-title
+          Custom notification events
+      .modal-body
+        .container-fluid
+          = form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, html: { class: "custom-notifications-form" } do |f|
+            = hidden_field_tag "custom_events", "true"
+            = f.hidden_field :level
+            .row
+              .col-lg-3
+                %h4.prepend-top-0
+                  Notification events
+              .col-lg-9
+                - NotificationSetting::EMAIL_EVENTS.each do |event, index|
+                  = index
+                  .form-group
+                    .checkbox{ class: ("prepend-top-0" if index == 0) }
+                      %label{ for: "events_#{event}" }
+                        = check_box_tag "events[#{event}]", true, @notification_setting.events[event], id: "events_#{event}", class: "js-custom-notification-event"
+                        %strong
+                          = event.to_s.humanize
+                          = icon("spinner spin", class: "custom-notification-event-loading")
diff --git a/app/views/shared/projects/_notification_dropdown.html.haml b/app/views/shared/projects/_notification_dropdown.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..438fde7771dc3c2ff1740f4fd1b12b620ba81b33
--- /dev/null
+++ b/app/views/shared/projects/_notification_dropdown.html.haml
@@ -0,0 +1,9 @@
+%ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
+  - NotificationSetting.levels.each do |level|
+    - if level.first != "custom"
+      = notification_list_item(level.first, @notification_setting)
+  - if @notification_setting.level != "custom"
+    %li.divider
+    %li
+      %a.update-notification{ href: "#", role: "button", data: { toggle: "modal", target: "#custom-notifications-modal", notification_level: "custom", notification_title: "Custom" } }
+        Custom
diff --git a/db/schema.rb b/db/schema.rb
index c7eeaadb1315394476896700c9dc9f76e9a88e69..6d648ec0692156a9904cc2974b8b95574ef3bd04 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
 #
 # It's strongly recommended that you check this file into your version control system.
 
-ActiveRecord::Schema.define(version: 20160528043124) do
+ActiveRecord::Schema.define(version: 20160531183627) do
 
   # These are extensions that must be enabled in order to support this database
   enable_extension "plpgsql"
@@ -43,46 +43,47 @@
     t.datetime "created_at"
     t.datetime "updated_at"
     t.string   "home_page_url"
-    t.integer  "default_branch_protection",         default: 2
+    t.integer  "default_branch_protection",             default: 2
     t.text     "restricted_visibility_levels"
-    t.boolean  "version_check_enabled",             default: true
-    t.integer  "max_attachment_size",               default: 10,          null: false
+    t.boolean  "version_check_enabled",                 default: true
+    t.integer  "max_attachment_size",                   default: 10,          null: false
     t.integer  "default_project_visibility"
     t.integer  "default_snippet_visibility"
     t.text     "restricted_signup_domains"
-    t.boolean  "user_oauth_applications",           default: true
+    t.boolean  "user_oauth_applications",               default: true
     t.string   "after_sign_out_path"
-    t.integer  "session_expire_delay",              default: 10080,       null: false
+    t.integer  "session_expire_delay",                  default: 10080,       null: false
     t.text     "import_sources"
     t.text     "help_page_text"
     t.string   "admin_notification_email"
-    t.boolean  "shared_runners_enabled",            default: true,        null: false
-    t.integer  "max_artifacts_size",                default: 100,         null: false
+    t.boolean  "shared_runners_enabled",                default: true,        null: false
+    t.integer  "max_artifacts_size",                    default: 100,         null: false
     t.string   "runners_registration_token"
-    t.boolean  "require_two_factor_authentication", default: false
-    t.integer  "two_factor_grace_period",           default: 48
-    t.boolean  "metrics_enabled",                   default: false
-    t.string   "metrics_host",                      default: "localhost"
-    t.integer  "metrics_pool_size",                 default: 16
-    t.integer  "metrics_timeout",                   default: 10
-    t.integer  "metrics_method_call_threshold",     default: 10
-    t.boolean  "recaptcha_enabled",                 default: false
+    t.boolean  "require_two_factor_authentication",     default: false
+    t.integer  "two_factor_grace_period",               default: 48
+    t.boolean  "metrics_enabled",                       default: false
+    t.string   "metrics_host",                          default: "localhost"
+    t.integer  "metrics_pool_size",                     default: 16
+    t.integer  "metrics_timeout",                       default: 10
+    t.integer  "metrics_method_call_threshold",         default: 10
+    t.boolean  "recaptcha_enabled",                     default: false
     t.string   "recaptcha_site_key"
     t.string   "recaptcha_private_key"
-    t.integer  "metrics_port",                      default: 8089
-    t.boolean  "akismet_enabled",                   default: false
+    t.integer  "metrics_port",                          default: 8089
+    t.boolean  "akismet_enabled",                       default: false
     t.string   "akismet_api_key"
-    t.integer  "metrics_sample_interval",           default: 15
-    t.boolean  "sentry_enabled",                    default: false
+    t.integer  "metrics_sample_interval",               default: 15
+    t.boolean  "sentry_enabled",                        default: false
     t.string   "sentry_dsn"
-    t.boolean  "email_author_in_body",              default: false
+    t.boolean  "email_author_in_body",                  default: false
     t.integer  "default_group_visibility"
-    t.boolean  "repository_checks_enabled",         default: false
+    t.boolean  "repository_checks_enabled",             default: false
     t.text     "shared_runners_text"
-    t.integer  "metrics_packet_size",               default: 1
+    t.integer  "metrics_packet_size",                   default: 1
     t.text     "disabled_oauth_sign_in_sources"
     t.string   "health_check_access_token"
-    t.boolean  "send_user_confirmation_email",      default: false
+    t.boolean  "send_user_confirmation_email",          default: false
+    t.integer  "container_registry_token_expire_delay", default: 5
   end
 
   create_table "audit_events", force: :cascade do |t|
@@ -639,6 +640,7 @@
     t.integer  "updated_by_id"
     t.boolean  "is_award",      default: false, null: false
     t.string   "type"
+    t.string   "system_type"
   end
 
   add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
@@ -661,6 +663,7 @@
     t.integer  "level",       default: 0, null: false
     t.datetime "created_at",              null: false
     t.datetime "updated_at",              null: false
+    t.text     "events"
   end
 
   add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index a1785311c2b8aef2cc5855e6513425205ba5abaf..98b57e5cbfbe21766426c3854520d6544a487bf0 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -126,7 +126,7 @@ class Spinach::Features::Project < Spinach::FeatureSteps
   end
 
   step 'I click notifications drop down button' do
-    click_link 'notifications-button'
+    first('.notifications-btn').click
   end
 
   step 'I choose Mention setting' do