Implement the 'seen comments' functionality (red dot) for the comments [SCI-5253]

This commit is contained in:
Oleksii Kriuchykhin 2020-11-30 15:55:20 +01:00
parent 2c8adc9496
commit 62374bee0a
14 changed files with 64 additions and 12 deletions

View file

@ -254,4 +254,8 @@ module CommentHelper
project: result.my_module.experiment.project, project: result.my_module.experiment.project,
message_items: { result: result.id }) message_items: { result: result.id })
end end
def has_unseen_comments?(commentable)
commentable.comments.where('? = ANY (unseen_by)', current_user.id).any?
end
end end

View file

@ -60,4 +60,10 @@ class Comment < ApplicationRecord
.offset((page - 1) * Constants::SEARCH_LIMIT) .offset((page - 1) * Constants::SEARCH_LIMIT)
end end
end end
def self.mark_as_seen_by(user)
# rubocop:disable Rails/SkipsModelValidations
all.where('? = ANY (unseen_by)', user.id).update_all("unseen_by = array_remove(unseen_by, #{user.id.to_i}::bigint)")
# rubocop:enable Rails/SkipsModelValidations
end
end end

View file

@ -249,7 +249,7 @@ class MyModule < ApplicationRecord
.where('comments.id < ?', last_id) .where('comments.id < ?', last_id)
.order(created_at: :desc) .order(created_at: :desc)
.limit(per_page) .limit(per_page)
comments.reverse TaskComment.from(comments, :comments).order(created_at: :asc)
end end
def last_activities(last_id = 1, def last_activities(last_id = 1,

View file

@ -164,7 +164,7 @@ class Project < ApplicationRecord
.where('comments.id < ?', last_id) .where('comments.id < ?', last_id)
.order(created_at: :desc) .order(created_at: :desc)
.limit(per_page) .limit(per_page)
comments.reverse ProjectComment.from(comments, :comments).order(created_at: :asc)
end end
def unassigned_users def unassigned_users

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class ProjectComment < Comment class ProjectComment < Comment
before_create :fill_unseen_by
belongs_to :project, foreign_key: :associated_id, inverse_of: :project_comments, touch: true belongs_to :project, foreign_key: :associated_id, inverse_of: :project_comments, touch: true
validates :project, presence: true validates :project, presence: true
@ -8,4 +10,10 @@ class ProjectComment < Comment
def commentable def commentable
project project
end end
private
def fill_unseen_by
self.unseen_by += project.users.where.not(id: user.id).pluck(:id)
end
end end

View file

@ -76,7 +76,7 @@ class Result < ApplicationRecord
.where('comments.id < ?', last_id) .where('comments.id < ?', last_id)
.order(created_at: :desc) .order(created_at: :desc)
.limit(per_page) .limit(per_page)
comments.reverse ResultComment.from(comments, :comments).order(created_at: :asc)
end end
def is_text def is_text

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class ResultComment < Comment class ResultComment < Comment
before_create :fill_unseen_by
belongs_to :result, foreign_key: :associated_id, inverse_of: :result_comments, touch: true belongs_to :result, foreign_key: :associated_id, inverse_of: :result_comments, touch: true
validates :result, presence: true validates :result, presence: true
@ -8,4 +10,10 @@ class ResultComment < Comment
def commentable def commentable
result result
end end
private
def fill_unseen_by
self.unseen_by += result.my_module.experiment.project.users.where.not(id: user.id).pluck(:id)
end
end end

View file

@ -102,7 +102,7 @@ class Step < ApplicationRecord
.where('comments.id < ?', last_id) .where('comments.id < ?', last_id)
.order(created_at: :desc) .order(created_at: :desc)
.limit(per_page) .limit(per_page)
comments.reverse StepComment.from(comments, :comments).order(created_at: :asc)
end end
def save(current_user=nil) def save(current_user=nil)

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class StepComment < Comment class StepComment < Comment
before_create :fill_unseen_by
belongs_to :step, foreign_key: :associated_id, inverse_of: :step_comments, touch: true belongs_to :step, foreign_key: :associated_id, inverse_of: :step_comments, touch: true
validates :step, presence: true validates :step, presence: true
@ -8,4 +10,10 @@ class StepComment < Comment
def commentable def commentable
step step
end end
private
def fill_unseen_by
self.unseen_by += step.protocol.my_module.experiment.project.users.where.not(id: user.id).pluck(:id)
end
end end

View file

@ -1,6 +1,8 @@
# frozen_string_literal: true # frozen_string_literal: true
class TaskComment < Comment class TaskComment < Comment
before_create :fill_unseen_by
belongs_to :my_module, foreign_key: :associated_id, inverse_of: :task_comments belongs_to :my_module, foreign_key: :associated_id, inverse_of: :task_comments
validates :my_module, presence: true validates :my_module, presence: true
@ -8,4 +10,10 @@ class TaskComment < Comment
def commentable def commentable
my_module my_module
end end
private
def fill_unseen_by
self.unseen_by += my_module.experiment.project.users.where.not(id: user.id).pluck(:id)
end
end end

View file

@ -1,7 +1,7 @@
<% cache [current_user, project] do %> <% cache [current_user, project] do %>
<% active = !project.archived %> <% active = !project.archived %>
<% if (active && (can_manage_project?(project) || can_archive_project?(project))) || (!active && can_restore_project?(project)) %> <% if (active && (can_manage_project?(project) || can_archive_project?(project))) || (!active && can_restore_project?(project)) %>
<div class="dropdown project-actions-menu new-comments"> <div class="dropdown project-actions-menu <%= 'new-comments' if has_unseen_comments?(project) %>">
<button class="btn btn-light dropdown-toggle icon-btn" type="button" id="projectActionsDropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> <button class="btn btn-light dropdown-toggle icon-btn" type="button" id="projectActionsDropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fas fa-ellipsis-h"></i> <i class="fas fa-ellipsis-h"></i>
</button> </button>

View file

@ -1,4 +1,4 @@
<div class="comments-container" data-object-id = <%= object.id %>> <div class="comments-container" data-object-id = <%= object.id %>>
<% per_page = Constants::COMMENTS_SEARCH_LIMIT %> <% per_page = Constants::COMMENTS_SEARCH_LIMIT %>
<div class="content-comments inline_scroll_block"> <div class="content-comments inline_scroll_block">
<% if comments.size == per_page %> <% if comments.size == per_page %>
@ -12,15 +12,16 @@
<% end %> <% end %>
<div class="comments-list"> <div class="comments-list">
<%= render partial: 'shared/comments/list.html.erb', locals: { comments: comments} %> <%= render partial: 'shared/comments/list.html.erb', locals: { comments: comments} %>
<% comments.mark_as_seen_by(current_user) %>
</div> </div>
</div> </div>
<% if can_create_comments %> <% if can_create_comments %>
<div class="new-message-container" data-create-url="<%= create_url %>"> <div class="new-message-container" data-create-url="<%= create_url %>">
<%= text_area_tag 'message', '', placeholder: t('general.comment_placeholder_new'), <%= text_area_tag 'message', '', placeholder: t('general.comment_placeholder_new'),
class: 'form-control smart-text-area textarea-sm', class: 'form-control smart-text-area textarea-sm',
data: { 'atwho-edit' => '' } %> data: { 'atwho-edit' => '' } %>
<i class="fas fa-paper-plane new-comment-button"></i> <i class="fas fa-paper-plane new-comment-button"></i>
<span class="new-message-error"></span> <span class="new-message-error"></span>
</div> </div>
<% end %> <% end %>
</div> </div>

View file

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddUnseenByToComments < ActiveRecord::Migration[6.0]
def change
add_column :comments, :unseen_by, :bigint, array: true, default: []
end
end

View file

@ -332,7 +332,8 @@ CREATE TABLE public.comments (
updated_at timestamp without time zone NOT NULL, updated_at timestamp without time zone NOT NULL,
last_modified_by_id bigint, last_modified_by_id bigint,
type character varying, type character varying,
associated_id integer associated_id integer,
unseen_by bigint[] DEFAULT '{}'::bigint[]
); );
@ -7062,6 +7063,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20200714082503'), ('20200714082503'),
('20200826143431'), ('20200826143431'),
('20200909121441'), ('20200909121441'),
('20201028103608'); ('20201028103608'),
('20201126203713');