Skip to content

Commit 597a827

Browse files
fblupialexrlpz
andcommitted
Improve comments performance (decidim#16073)
Co-authored-by: Alejandro Rueda <alejandro.rueda@nazaries.com>
1 parent 483abd7 commit 597a827

32 files changed

Lines changed: 1148 additions & 496 deletions

File tree

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
<%= render partial: "decidim/comments/comments/delete", formats: [:html], locals: { comment: model } %>
22

3-
<div data-comment-footer data-controller="accordion" id="accordion-<%= model.id %>">
4-
<div id="comment-<%= model.id %>-replies" class="<%= "comment-reply" if has_replies_in_children? %>">
5-
<% if has_replies_in_children? %>
6-
<%= render :replies %>
7-
<% end %>
8-
</div>
9-
</div>
3+
<% if has_replies_in_children? %>
4+
<%= render :replies %>
5+
<% end %>
Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1-
<% replies.each do |reply| %>
2-
<%= cell("decidim/comments/comment", reply, root_depth: , order: , reloaded: reloaded?) %>
3-
<% end %>
1+
<div data-controller="show-replies"
2+
data-show-replies-url-value="<%= decidim_comments.comments_path %>"
3+
data-show-replies-comment-gid-value="<%= model.to_signed_global_id.to_s %>"
4+
data-show-replies-order-value="<%= order %>"
5+
data-show-replies-loaded-value="false">
6+
<div class="show-replies-button">
7+
<button class="button button__xs button__text-secondary"
8+
data-action="click->show-replies#toggle"
9+
data-show-replies-target="button"
10+
aria-expanded="false"
11+
aria-controls="comment-<%= model.id %>-replies"
12+
id="comment-<%= model.id %>-replies-trigger">
13+
<span class="font-normal"><%= t("decidim.components.comment.replies_count", count: replies_count) %></span>
14+
<%= icon "arrow-down-s-line" %>
15+
<%= icon "arrow-up-s-line" %>
16+
</button>
17+
<span data-show-replies-target="spinner" class="ml-2 hidden"><%= icon "loader-3-line", class: "animate-spin fill-secondary" %></span>
18+
</div>
19+
<div id="comment-<%= model.id %>-replies"
20+
data-show-replies-target="container"
21+
class="comment-reply hidden">
22+
</div>
23+
</div>

decidim-comments/app/cells/decidim/comments/comment/show.erb

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,31 +90,17 @@
9090
<%= votes %>
9191
</div>
9292
</div>
93-
<div class="comment__reply-button">
94-
<% if depth.zero? && has_replies_in_children? %>
95-
<button class="button button__xs button__transparent-secondary border-white absolute top-4" data-comment-hide data-controls="comment-<%= model.id %>-replies" data-open="false" id="comment-<%= model.id %>-replies-trigger">
96-
<span data-show-comment-reply class="font-normal" aria-label="<%= t("decidim.components.comment.show_replies", count: replies.size) %>">
97-
<%= t("decidim.components.comment.answers", count: replies.size) %>
98-
</span>
99-
<%= icon "arrow-down-s-line" %>
100-
<span data-hide-comment-reply class="font-normal" aria-label="<%= t("decidim.components.comment.hide_replies", count: replies.size) %>">
101-
<%= t("decidim.components.comment.answers", count: replies.size) %>
102-
</span>
103-
<%= icon "arrow-up-s-line" %>
104-
</button>
105-
<% end %>
106-
</div>
10793
<% if can_reply? %>
10894
<div id="panel-<%= reply_id %>" class="add-comment" data-additional-reply>
10995
<%== cell("decidim/comments/comment_form", model, root_depth:, order:) %>
11096
</div>
11197
<% end %>
112-
<div id="comment-<%= model.id %>-replies" class="<%= "comment-reply" if has_replies_in_children? %>">
113-
<% if has_replies_in_children? %>
114-
<%= render :replies %>
115-
<% end %>
116-
</div>
11798
</div>
99+
<% if has_replies_in_children? %>
100+
<%= render :replies %>
101+
<% elsif can_reply? %>
102+
<div id="comment-<%= model.id %>-replies" class="comment-reply"></div>
103+
<% end %>
118104
<% end %>
119105
<% if current_user.present? %>
120106
<%= cell("decidim/report_button", model, modal_id: "flagModalComment#{model.id}").flag_modal %>

decidim-comments/app/cells/decidim/comments/comment_cell.rb

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ def comment_body
8686
formatted_body
8787
end
8888

89-
def replies
90-
SortedComments.for(model, order_by: order)
91-
end
92-
9389
def order
9490
options[:order] || "older"
9591
end
@@ -234,7 +230,11 @@ def has_replies?
234230
end
235231

236232
def has_replies_in_children?
237-
model.descendants.where(decidim_commentable_type: "Decidim::Comments::Comment").not_hidden.not_deleted.exists?
233+
replies_count.positive?
234+
end
235+
236+
def replies_count
237+
@replies_count ||= model.replies.count
238238
end
239239

240240
# action_authorization_button expects current_component to be available

decidim-comments/app/cells/decidim/comments/comment_form/show.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<% end %>
3232
<div class="<%= reply? ? "" : "publish-comment-button" %>">
3333
<button type="submit"
34-
class="button button__sm button__secondary <%= reply? ? "w-full" : "h-9 close-comment-fullscreen" %>"
34+
class="button button__sm button__secondary <%= reply? ? "" : "h-9 close-comment-fullscreen" %>"
3535
disabled="disabled">
3636
<span>
3737
<%= reply? ? t("decidim.components.add_comment_form.form.submit_reply") : t("decidim.components.add_comment_form.form.submit_root_comment") %>
Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<div id="comments">
22
<div class="comments">
3-
<div class="comments__header">
3+
<% if user_signed_in? %>
4+
<button class="button button__lg button__secondary flex md:hidden w-full h-9 text-sm add-comment-mobile">
5+
<%= t("add_comment", scope: "decidim.components.add_comment_form") %>
6+
</button>
7+
<% end %>
8+
<%= add_comment %>
9+
<%= user_comments_blocked_warning %>
10+
<div class="comments__header mt-8">
411
<h2 class="h4">
512
<% if single_comment? %>
613
<%= t("decidim.components.comments.comment_details_title") %>
@@ -11,18 +18,14 @@
1118
</span>
1219
<% end %>
1320
</h2>
14-
<%= render :order_control unless two_columns_layout? %>
21+
<% if two_columns_layout? %>
22+
<div class="md:hidden"><%= render :order_control %></div>
23+
<% else %>
24+
<%= render :order_control %>
25+
<% end %>
1526
</div>
1627
<%= single_comment_warning %>
1728
<%= blocked_comments_warning %>
1829
<%= render_comments %>
19-
<% if user_signed_in? %>
20-
<button class="button button__lg button__secondary flex md:hidden w-full h-9 text-sm add-comment-mobile">
21-
<%= t("add_comment", scope: "decidim.components.add_comment_form") %>
22-
</button>
23-
<% end %>
24-
<%= add_comment %>
25-
<%= user_comments_blocked_warning %>
2630
</div>
27-
<%= cell("decidim/announcement", t("decidim.components.comments.loading"), callout_class: "primary loading-comments hidden") %>
2831
</div>

decidim-comments/app/cells/decidim/comments/comments_cell.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def available_orders
108108
end
109109

110110
def order
111-
options[:order] || "older"
111+
options[:order] || (two_columns_layout? ? "recent" : "older")
112112
end
113113

114114
def decidim

decidim-comments/app/cells/decidim/comments/two_columns_comments/column.erb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@
1414
<% @comments.each do |comment| %>
1515
<%= cell("decidim/comments/comment_thread", comment, order:) %>
1616
<% end %>
17-
<% else %>
18-
<p class="comments-section__no-comments"><%= @no_comments_message %></p>
17+
<% elsif @top_comment.blank? %>
18+
<p class="comments-section__no-comments"><%= t("decidim.components.comments.no_comments_yet") %></p>
19+
<% end %>
20+
21+
<% if @has_more %>
22+
<% offset = @comments.size + (@top_comment.present? ? 1 : 0) %>
23+
<%= controller.view_context.render partial: "decidim/comments/comments/load_more_comments", locals: { commentable: model, order:, offset:, alignment: @alignment } %>
1924
<% end %>
2025
</div>
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
<div id="desktopContainer" class="comments-two-columns card__grid-grid hidden md:grid">
2-
<%= render_column(@top_comment_in_favor, @sorted_comments_in_favor, "thumb-up-line", t("decidim.components.comments.in_favor")) %>
3-
<%= render_column(@top_comment_against, @sorted_comments_against, "thumb-down-line", t("decidim.components.comments.against")) %>
2+
<%= render_column(@top_comment_in_favor, @sorted_comments_in_favor, "thumb-up-line", t("decidim.components.comments.in_favor"), 1, @has_more_in_favor) %>
3+
<%= render_column(@top_comment_against, @sorted_comments_against, "thumb-down-line", t("decidim.components.comments.against"), -1, @has_more_against) %>
44
</div>
55

66
<div id="mobileContainer" class="comment-threads block md:hidden" aria-live="polite">
77
<%= comments_loading %>
8-
<% @interleaved_comments.each do |comment| %>
9-
<%= cell("decidim/comments/comment_thread", comment, order:, top_comment: (comment == @top_comment_in_favor || comment == @top_comment_against)) %>
8+
<% @mobile_comments.each do |comment| %>
9+
<%= cell("decidim/comments/comment_thread", comment, order:) %>
10+
<% end %>
11+
<% if @has_more_mobile %>
12+
<%= controller.view_context.render partial: "decidim/comments/comments/load_more_comments", locals: { commentable: model, order:, offset: @mobile_comments.size } %>
1013
<% end %>
1114
</div>

decidim-comments/app/cells/decidim/comments/two_columns_comments_cell.rb

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,34 +6,41 @@ module Comments
66
class TwoColumnsCommentsCell < Decidim::Comments::CommentsCell
77
def call
88
initialize_comments
9-
@interleaved_comments = interleave_comments(@sorted_comments_in_favor, @sorted_comments_against)
109
render :show
1110
end
1211

13-
def render_column(top_comment, comments, icon_name, title)
14-
set_column_variables(top_comment, comments, icon_name, title)
12+
# rubocop:disable Metrics/ParameterLists
13+
def render_column(top_comment, comments, icon_name, title, alignment, has_more)
14+
set_column_variables(top_comment, comments, icon_name, title, alignment, has_more)
1515
render :column
1616
end
17+
# rubocop:enable Metrics/ParameterLists
1718

1819
private
1920

2021
def initialize_comments
2122
if model.closed?
2223
load_closed_comments
2324
else
24-
@sorted_comments_in_favor = comments_in_favor
25-
@sorted_comments_against = comments_against
25+
@sorted_comments_in_favor = comments_in_favor_query.query
26+
@sorted_comments_against = comments_against_query.query
2627
end
28+
29+
counts = comments_count_by_alignment
30+
@has_more_in_favor = (counts[1] || 0) > comments_in_favor_query.offset + comments_in_favor_query.limit
31+
@has_more_against = (counts[-1] || 0) > comments_against_query.offset + comments_against_query.limit
32+
33+
load_mobile_comments(counts.values.sum)
2734
end
2835

2936
def load_closed_comments
30-
@top_comment_in_favor, @sorted_comments_in_favor = sorted_comments(comments_in_favor)
31-
@top_comment_against, @sorted_comments_against = sorted_comments(comments_against)
37+
@top_comment_in_favor, @sorted_comments_in_favor = sorted_comments(comments_in_favor_query.query)
38+
@top_comment_against, @sorted_comments_against = sorted_comments(comments_against_query.query)
3239
end
3340

3441
def sorted_comments(comments)
3542
top_comment = find_top_comment(comments)
36-
sorted_comments = comments.where.not(id: top_comment&.id).order(created_at: :asc)
43+
sorted_comments = comments.where.not(id: top_comment&.id)
3744
[top_comment, sorted_comments]
3845
end
3946

@@ -45,42 +52,34 @@ def find_top_comment(comments)
4552
.first
4653
end
4754

48-
def interleave_comments(comments_in_favor, comments_against)
49-
interleave_top_comments + interleave_remaining_comments(comments_in_favor, comments_against)
50-
end
51-
52-
def interleave_top_comments
53-
return [] unless model.closed?
54-
55-
Array(@top_comment_in_favor) + Array(@top_comment_against)
55+
def comments_in_favor_query
56+
@comments_in_favor_query ||= SortedComments.new(model, order_by: order, alignment: 1, offset: 0)
5657
end
5758

58-
def interleave_remaining_comments(comments_in_favor, comments_against)
59-
interleaved = []
60-
max_length = [comments_in_favor.size, comments_against.size].max
61-
62-
max_length.times do |i|
63-
interleaved << comments_in_favor[i] if comments_in_favor[i]
64-
interleaved << comments_against[i] if comments_against[i]
65-
end
66-
67-
interleaved
59+
def comments_against_query
60+
@comments_against_query ||= SortedComments.new(model, order_by: order, alignment: -1, offset: 0)
6861
end
6962

70-
def comments_in_favor
71-
@comments_in_favor ||= model.comments.positive.order(:created_at)
63+
def load_mobile_comments(total_count)
64+
@sorted_comments_query = SortedComments.new(model, order_by: order, offset: 0)
65+
@mobile_comments = @sorted_comments_query.query
66+
@has_more_mobile = total_count > @sorted_comments_query.offset + @sorted_comments_query.limit
7267
end
7368

74-
def comments_against
75-
@comments_against ||= model.comments.negative.order(:created_at)
69+
def comments_count_by_alignment
70+
@comments_count_by_alignment ||= Decidim::Comments::Comment.where(commentable: model).group(:alignment).count
7671
end
7772

78-
def set_column_variables(top_comment, comments, icon_name, title)
73+
# rubocop:disable Metrics/ParameterLists
74+
def set_column_variables(top_comment, comments, icon_name, title, alignment, has_more)
7975
@top_comment = top_comment
8076
@comments = comments
8177
@icon_name = icon_name
8278
@title = title
79+
@alignment = alignment
80+
@has_more = has_more
8381
end
82+
# rubocop:enable Metrics/ParameterLists
8483
end
8584
end
8685
end

0 commit comments

Comments
 (0)