Commit 359157c0 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Introduce NotificationSetting to user interface

* visiting project will create notification setting if missing
* change notification setting per project even without membership
* use notification settings instead of membership on profile page
Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
parent 73c5a341
...@@ -37,15 +37,9 @@ class @Project ...@@ -37,15 +37,9 @@ class @Project
$('.update-notification').on 'click', (e) -> $('.update-notification').on 'click', (e) ->
e.preventDefault() e.preventDefault()
notification_level = $(@).data 'notification-level' notification_level = $(@).data 'notification-level'
label = $(@).data 'notification-title'
$('#notification_level').val(notification_level) $('#notification_level').val(notification_level)
$('#notification-form').submit() $('#notification-form').submit()
label = null
switch notification_level
when 0 then label = ' Disabled '
when 1 then label = ' Participating '
when 2 then label = ' Watching '
when 3 then label = ' Global '
when 4 then label = ' On Mention '
$('#notifications-button').empty().append("<i class='fa fa-bell'></i>" + label + "<i class='fa fa-angle-down'></i>") $('#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' $(@).parents('ul').find('li.active').removeClass 'active'
$(@).parent().addClass 'active' $(@).parent().addClass 'active'
......
...@@ -2,8 +2,8 @@ class Profiles::NotificationsController < Profiles::ApplicationController ...@@ -2,8 +2,8 @@ class Profiles::NotificationsController < Profiles::ApplicationController
def show def show
@user = current_user @user = current_user
@notification = current_user.notification @notification = current_user.notification
@project_members = current_user.project_members @group_notifications = current_user.notification_settings.for_groups
@group_members = current_user.group_members @project_notifications = current_user.notification_settings.for_projects
end end
def update def update
...@@ -11,14 +11,10 @@ class Profiles::NotificationsController < Profiles::ApplicationController ...@@ -11,14 +11,10 @@ class Profiles::NotificationsController < Profiles::ApplicationController
@saved = if type == 'global' @saved = if type == 'global'
current_user.update_attributes(user_params) current_user.update_attributes(user_params)
elsif type == 'group'
group_member = current_user.group_members.find(params[:notification_id])
group_member.notification_level = params[:notification_level]
group_member.save
else else
project_member = current_user.project_members.find(params[:notification_id]) notification_setting = current_user.notification_settings.find(params[:notification_id])
project_member.notification_level = params[:notification_level] notification_setting.level = params[:notification_level]
project_member.save notification_setting.save
end end
respond_to do |format| respond_to do |format|
......
...@@ -98,14 +98,23 @@ class ProjectsController < Projects::ApplicationController ...@@ -98,14 +98,23 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
if @project.repository_exists?
if @project.empty_repo?
render 'projects/empty'
else
if current_user if current_user
@membership = @project.team.find_member(current_user.id) @membership = @project.team.find_member(current_user.id)
if @membership
@notification_setting = current_user.notification_settings.find_or_initialize_by(source: @project)
unless @notification_setting.persisted?
@notification_setting.set_defaults
@notification_setting.save
end
end
end end
if @project.repository_exists?
if @project.empty_repo?
render 'projects/empty'
else
render :show render :show
end end
else else
......
module NotificationsHelper module NotificationsHelper
include IconsHelper include IconsHelper
def notification_icon(notification) def notification_icon_class(level)
if notification.disabled? case level.to_sym
icon('volume-off', class: 'ns-mute') when :disabled
elsif notification.participating? 'microphone-slash'
icon('volume-down', class: 'ns-part') when :participating
elsif notification.watch? 'volume-up'
icon('volume-up', class: 'ns-watch') when :watch
else 'eye'
icon('circle-o', class: 'ns-default') when :mention
'at'
when :global
'globe'
end end
end end
def notification_list_item(notification_level, user_membership) def notification_icon(level)
case notification_level icon("#{notification_icon_class(level)} fw")
when Notification::N_DISABLED end
update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash')
when Notification::N_PARTICIPATING def notification_title(level)
update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up') case level.to_sym
when Notification::N_WATCH when :disabled
update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye') 'Disabled'
when Notification::N_MENTION when :participating
update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at') 'Participate'
when Notification::N_GLOBAL when :watch
update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe') 'Watch'
else when :mention
# do nothing 'On mention'
when :global
'Global'
end end
end end
def update_notification_link(notification_level, user_membership, title, icon) def notification_list_item(level, setting)
content_tag(:li, class: active_level_for(user_membership, notification_level)) do title = notification_title(level)
link_to '#', class: 'update-notification', data: { notification_level: notification_level } do
icon("#{icon} fw", text: title) data = {
notification_level: level,
notification_title: title
}
content_tag(:li, class: active_level_for(setting, level)) do
link_to '#', class: 'update-notification', data: data do
icon("#{notification_icon_class(level)} fw", text: title)
end end
end end
end end
def notification_label(user_membership) def notification_label(setting)
Notification.new(user_membership).to_s notification_title(setting.level)
end end
def active_level_for(user_membership, level) def active_level_for(setting, level)
'active' if user_membership.notification_level == level 'active' if setting.level == level
end end
end end
...@@ -11,4 +11,11 @@ class NotificationSetting < ActiveRecord::Base ...@@ -11,4 +11,11 @@ class NotificationSetting < ActiveRecord::Base
# Notification level # Notification level
# Note: When adding an option, it MUST go on the end of the array. # Note: When adding an option, it MUST go on the end of the array.
enum level: [:disabled, :participating, :watch, :global, :mention] enum level: [:disabled, :participating, :watch, :global, :mention]
scope :for_groups, -> { where(source_type: 'Namespace') }
scope :for_projects, -> { where(source_type: 'Project') }
def set_defaults
self.level = :global
end
end end
...@@ -143,6 +143,7 @@ class User < ActiveRecord::Base ...@@ -143,6 +143,7 @@ class User < ActiveRecord::Base
has_many :spam_logs, dependent: :destroy has_many :spam_logs, dependent: :destroy
has_many :builds, dependent: :nullify, class_name: 'Ci::Build' has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
has_many :todos, dependent: :destroy has_many :todos, dependent: :destroy
has_many :notification_settings, dependent: :destroy
# #
# Validations # Validations
...@@ -157,7 +158,7 @@ class User < ActiveRecord::Base ...@@ -157,7 +158,7 @@ class User < ActiveRecord::Base
presence: true, presence: true,
uniqueness: { case_sensitive: false } uniqueness: { case_sensitive: false }
validates :notification_level, inclusion: { in: Notification.notification_levels }, presence: true validates :notification_level, presence: true
validate :namespace_uniq, if: ->(user) { user.username_changed? } validate :namespace_uniq, if: ->(user) { user.username_changed? }
validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? } validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
validate :unique_email, if: ->(user) { user.email_changed? } validate :unique_email, if: ->(user) { user.email_changed? }
...@@ -190,6 +191,10 @@ class User < ActiveRecord::Base ...@@ -190,6 +191,10 @@ class User < ActiveRecord::Base
# Note: When adding an option, it MUST go on the end of the array. # Note: When adding an option, it MUST go on the end of the array.
enum project_view: [:readme, :activity, :files] enum project_view: [:readme, :activity, :files]
# Notification level
# Note: When adding an option, it MUST go on the end of the array.
enum notification_level: [:disabled, :participating, :watch, :global, :mention]
alias_attribute :private_token, :authentication_token alias_attribute :private_token, :authentication_token
delegate :path, to: :namespace, allow_nil: true, prefix: true delegate :path, to: :namespace, allow_nil: true, prefix: true
......
%li.notification-list-item %li.notification-list-item
%span.notification.fa.fa-holder.append-right-5 %span.notification.fa.fa-holder.append-right-5
- if notification.global? - if setting.global?
= notification_icon(@notification) = notification_icon(current_user.notification_level)
- else - else
= notification_icon(notification) = notification_icon(setting.level)
%span.str-truncated %span.str-truncated
- if membership.kind_of? GroupMember - if setting.source.kind_of? Project
= link_to membership.group.name, membership.group = link_to_project(setting.source)
- else - else
= link_to_project(membership.project) = link_to setting.source.name, group_path(setting.source)
.pull-right .pull-right
= form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do
= hidden_field_tag :notification_type, type, id: dom_id(membership, 'notification_type') = hidden_field_tag :notification_id, setting.id
= hidden_field_tag :notification_id, membership.id, id: dom_id(membership, 'notification_id') = hidden_field_tag :notification_level, setting.level
= select_tag :notification_level, options_for_select(Notification.options_with_labels, notification.level), class: 'form-control trigger-submit' = select_tag :notification_level, options_for_select(User.notification_levels.keys, setting.level), class: 'form-control trigger-submit'
...@@ -26,29 +26,29 @@ ...@@ -26,29 +26,29 @@
.form-group .form-group
= f.label :notification_level, class: 'label-light' = f.label :notification_level, class: 'label-light'
.radio .radio
= f.label :notification_level, value: Notification::N_DISABLED do = f.label :notification_level, value: :disabled do
= f.radio_button :notification_level, Notification::N_DISABLED = f.radio_button :notification_level, :disabled
.level-title .level-title
Disabled Disabled
%p You will not get any notifications via email %p You will not get any notifications via email
.radio .radio
= f.label :notification_level, value: Notification::N_MENTION do = f.label :notification_level, value: :mention do
= f.radio_button :notification_level, Notification::N_MENTION = f.radio_button :notification_level, :mention
.level-title .level-title
On Mention On Mention
%p You will receive notifications only for comments in which you were @mentioned %p You will receive notifications only for comments in which you were @mentioned
.radio .radio
= f.label :notification_level, value: Notification::N_PARTICIPATING do = f.label :notification_level, value: :participating do
= f.radio_button :notification_level, Notification::N_PARTICIPATING = f.radio_button :notification_level, :participating
.level-title .level-title
Participating Participating
%p You will only receive notifications from related resources (e.g. from your commits or assigned issues) %p You will only receive notifications from related resources (e.g. from your commits or assigned issues)
.radio .radio
= f.label :notification_level, value: Notification::N_WATCH do = f.label :notification_level, value: :watch do
= f.radio_button :notification_level, Notification::N_WATCH = f.radio_button :notification_level, :watch
.level-title .level-title
Watch Watch
%p You will receive notifications for any activity %p You will receive notifications for any activity
...@@ -57,18 +57,16 @@ ...@@ -57,18 +57,16 @@
= f.submit 'Update settings', class: "btn btn-create" = f.submit 'Update settings', class: "btn btn-create"
%hr %hr
%h5 %h5
Groups (#{@group_members.count}) Groups (#{@group_notifications.count})
%div %div
%ul.bordered-list %ul.bordered-list
- @group_members.each do |group_member| - @group_notifications.each do |setting|
- notification = Notification.new(group_member) = render 'settings', setting: setting
= render 'settings', type: 'group', membership: group_member, notification: notification
%h5 %h5
Projects (#{@project_members.count}) Projects (#{@project_notifications.count})
%p.account-well %p.account-well
To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group. To specify the notification level per project of a group you belong to, you need to be a member of the project itself, not only its group.
.append-bottom-default .append-bottom-default
%ul.bordered-list %ul.bordered-list
- @project_members.each do |project_member| - @project_notifications.each do |setting|
- notification = Notification.new(project_member) = render 'settings', setting: setting
= render 'settings', type: 'project', membership: project_member, notification: notification
- case @membership - if @notification_setting
- when ProjectMember
= form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do
= hidden_field_tag :notification_type, 'project' = hidden_field_tag :notification_id, @notification_setting.id
= hidden_field_tag :notification_id, @membership.id = hidden_field_tag :notification_level, @notification_setting.level
= hidden_field_tag :notification_level
%span.dropdown %span.dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"} %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
= icon('bell') = icon('bell')
= notification_label(@membership) = notification_title(@notification_setting.level)
= icon('angle-down') = icon('angle-down')
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- Notification.project_notification_levels.each do |level| - NotificationSetting.levels.each do |level|
= notification_list_item(level, @membership) = notification_list_item(level.first, @notification_setting)
- when GroupMember
.btn.disabled.notifications-btn.has-tooltip{title: "To change the notification level, you need to be a member of the project itself, not only its group."}
= icon('bell')
= notification_label(@membership)
= icon('angle-down')
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