Skip to content

Commit 68ba2e2

Browse files
committed
Optimize a few small partials
We had many small partials which were mostly logic, and were repeated several times for each index row Moved these to be ruby helpers instead to speed up rendering This should result in 20-30% rendering speedup
1 parent 19deebd commit 68ba2e2

12 files changed

Lines changed: 252 additions & 208 deletions

app/helpers/topics_helper.rb

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
module TopicsHelper
2+
# Replaces app/views/topics/_participant_row.html.slim
3+
def participant_row_html(participant:, avatar_size: 40, tooltip: nil)
4+
alias_record = participant[:alias]
5+
return nil unless alias_record
6+
7+
person = participant[:person] || alias_record.person
8+
message_count = participant[:message_count]
9+
last_at = participant[:last_at]
10+
11+
tooltip_parts = []
12+
tooltip_parts << pluralize(message_count, "message") if message_count
13+
tooltip_parts << "last #{smart_time_display(last_at)}" if last_at
14+
role_label = person&.contributor_badge
15+
tooltip_parts << role_label if role_label
16+
tooltip = tooltip || (tooltip_parts.any? ? tooltip_parts.join(", ") : alias_record.name)
17+
18+
avatar_classes = ["participant-avatar"]
19+
20+
membership_icons = []
21+
membership_types = person&.contributor_membership_types || []
22+
membership_icons << { icon: "fa-solid fa-people-group", label: "Core Team" } if membership_types.include?("core_team")
23+
membership_icons << { icon: "fa-solid fa-code-branch", label: "Committer" } if membership_types.include?("committer")
24+
membership_icons << { icon: "fa-solid fa-star", label: "Major Contributor" } if membership_types.include?("major_contributor")
25+
membership_icons << { icon: "fa-solid fa-award", label: "Significant Contributor" } if membership_types.include?("significant_contributor")
26+
if membership_types.include?("past_major_contributor") || membership_types.include?("past_significant_contributor")
27+
membership_icons << { icon: "fa-solid fa-clock-rotate-left", label: "Past Contributor" }
28+
end
29+
30+
name_classes = ["participant-name-link"]
31+
name_classes << "is-committer" if membership_types.include?("committer")
32+
33+
left = tag.div(class: "participant-left") do
34+
link_to(person_path(alias_record.email), class: "participant-avatar-link") do
35+
image_tag(alias_record.gravatar_url(size: avatar_size), class: avatar_classes.join(" "), alt: alias_record.name, title: tooltip)
36+
end +
37+
tag.div(class: "participant-details") do
38+
tag.div(class: "participant-name") do
39+
link_to(alias_record.name, person_path(alias_record.email), class: name_classes.join(" "), title: tooltip)
40+
end
41+
end
42+
end
43+
44+
memberships = if membership_icons.any?
45+
tag.div(class: "participant-memberships") do
46+
safe_join(membership_icons.map { |entry|
47+
tag.span(class: "participant-icon", title: entry[:label]) do
48+
tag.i(class: entry[:icon])
49+
end
50+
})
51+
end
52+
end
53+
54+
tag.div(class: "participant-row", title: tooltip) do
55+
safe_join([left, memberships].compact)
56+
end
57+
end
58+
59+
# Replaces app/views/topics/_avatar_list.slim
60+
def avatar_list_html(participants:, total_participants:)
61+
avatars = tag.div(class: "participants-avatars") do
62+
avatar_tags = participants.filter_map do |participant|
63+
alias_record = participant[:alias] || participant
64+
next unless alias_record
65+
66+
person = participant[:person] || alias_record.person
67+
message_count = participant[:message_count]
68+
last_at = participant[:last_at]
69+
70+
tooltip_parts = [alias_record.name]
71+
tooltip_parts << pluralize(message_count, "message") if message_count
72+
tooltip_parts << "last #{smart_time_display(last_at)}" if last_at
73+
role_label = person&.contributor_badge
74+
tooltip_parts << role_label if role_label
75+
badge_text = tooltip_parts.join(", ")
76+
77+
css_classes = ["participant-avatar"]
78+
css_classes << "is-core-team" if person&.core_team?
79+
css_classes << "is-committer" if !person&.core_team? && person&.committer?
80+
css_classes << "is-major-contributor" if !person&.core_team? && !person&.committer? && person&.major_contributor?
81+
css_classes << "is-significant-contributor" if !person&.core_team? && !person&.committer? && !person&.major_contributor? && person&.significant_contributor?
82+
css_classes << "is-past-contributor" if person&.past_contributor?
83+
84+
link_to(person_path(alias_record.email), class: "participant-avatar-link") do
85+
image_tag(alias_record.gravatar_url(size: 32), class: css_classes.join(" "), alt: alias_record.name, title: badge_text)
86+
end
87+
end
88+
89+
overflow = if total_participants > participants.count
90+
tag.span("+#{total_participants - participants.count}", class: "participants-count")
91+
end
92+
93+
safe_join(avatar_tags) + (overflow || "".html_safe)
94+
end
95+
96+
tag.div(class: "participants") { avatars }
97+
end
98+
99+
# Replaces app/views/topics/_note_icon.html.slim
100+
def note_icon_html(topic:, count:)
101+
count = count.to_i
102+
classes = ["topic-icon", "activity-note"]
103+
classes << "is-hidden" unless count.positive?
104+
tooltip_label = count.positive? ? "Notes: #{count}" : "Notes"
105+
106+
tag.div(
107+
class: classes.join(" "),
108+
id: dom_id(topic, "notes"),
109+
title: tooltip_label,
110+
data: { controller: "hover-popover", hover_popover_delay_value: "200", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
111+
) do
112+
icon = tag.i(class: "fa-solid fa-note-sticky")
113+
badge = count.positive? ? tag.span(count, class: "topic-icon-badge") : nil
114+
safe_join([icon, badge].compact)
115+
end
116+
end
117+
118+
# Replaces app/views/topics/_star_icon.html.slim
119+
def star_icon_html(topic:, star_data:)
120+
star_data = star_data || {}
121+
starred_by_me = star_data[:starred_by_me] || false
122+
team_starrers = star_data[:team_starrers] || []
123+
total_count = (starred_by_me ? 1 : 0) + team_starrers.size
124+
125+
classes = ["topic-icon", "activity-star"]
126+
classes << "is-hidden" if total_count.zero?
127+
classes << "is-starred" if starred_by_me
128+
icon_class = starred_by_me ? "fa-solid fa-star" : "fa-regular fa-star"
129+
130+
tag.div(
131+
class: classes.join(" "),
132+
id: dom_id(topic, "stars"),
133+
data: { controller: "hover-popover", hover_popover_delay_value: "200", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
134+
) do
135+
parts = [tag.i(class: icon_class)]
136+
parts << tag.span(total_count, class: "topic-icon-badge") if total_count > 2
137+
138+
if starred_by_me || team_starrers.any?
139+
hover_rows = []
140+
if starred_by_me
141+
my_alias = current_user.person&.default_alias || current_user.aliases&.first
142+
if my_alias
143+
participant_stub = { alias: my_alias }
144+
role_label = my_alias.contributor_badge || "User"
145+
hover_rows << participant_row_html(participant: participant_stub, avatar_size: 32, tooltip: "#{my_alias.name} (#{role_label})")
146+
end
147+
end
148+
team_starrers.each do |alias_record|
149+
participant_stub = { alias: alias_record }
150+
role_label = alias_record.contributor_badge || "User"
151+
hover_rows << participant_row_html(participant: participant_stub, avatar_size: 32, tooltip: "#{alias_record.name} (#{role_label})")
152+
end
153+
parts << tag.div(
154+
class: "topic-icon-hover",
155+
data: { hover_popover_target: "popover", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
156+
) { safe_join(hover_rows.compact) }
157+
end
158+
159+
safe_join(parts)
160+
end
161+
end
162+
163+
# Replaces app/views/topics/_participation_icon.html.slim
164+
def participation_icon_html(topic:, participation:)
165+
participation = participation || {}
166+
classes = ["topic-icon", "activity-team"]
167+
classes << "is-mine" if participation[:mine]
168+
classes << "is-hidden" unless participation[:mine] || participation[:team]
169+
aliases = participation[:aliases] || []
170+
count = aliases.size
171+
172+
tag.div(
173+
class: classes.join(" "),
174+
id: dom_id(topic, "participation"),
175+
data: { controller: "hover-popover", hover_popover_delay_value: "200", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
176+
) do
177+
parts = [tag.i(class: "fa-solid fa-user-group")]
178+
parts << tag.span(count, class: "topic-icon-badge") if count > 1
179+
180+
if aliases.any?
181+
hover_rows = aliases.map do |alias_record|
182+
participant_stub = { alias: alias_record }
183+
role_label = alias_record.contributor_badge || "User"
184+
participant_row_html(participant: participant_stub, avatar_size: 32, tooltip: "#{alias_record.name} (#{role_label})")
185+
end
186+
parts << tag.div(
187+
class: "topic-icon-hover",
188+
data: { hover_popover_target: "popover", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
189+
) { safe_join(hover_rows.compact) }
190+
end
191+
192+
safe_join(parts)
193+
end
194+
end
195+
196+
# Replaces app/views/topics/_team_readers_icon.html.slim
197+
def team_readers_icon_html(topic:, readers:)
198+
count = readers&.size.to_i
199+
classes = ["topic-icon", "activity-team-read"]
200+
classes << "is-hidden" if count.zero?
201+
202+
tag.div(
203+
class: classes.join(" "),
204+
id: dom_id(topic, "team_readers"),
205+
data: { controller: "hover-popover", hover_popover_delay_value: "200", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
206+
) do
207+
parts = [tag.i(class: "fa-solid fa-users")]
208+
209+
if count.positive?
210+
parts << tag.span(count, class: "topic-icon-badge")
211+
212+
hover_rows = readers.filter_map do |reader|
213+
alias_record = reader[:user]&.person&.default_alias || reader[:user]&.aliases&.first
214+
next unless alias_record
215+
216+
participant_stub = { alias: alias_record }
217+
role_label = alias_record.contributor_badge || "User"
218+
participant_row_html(participant: participant_stub, avatar_size: 32, tooltip: "#{alias_record.name} (#{reader[:status]}, #{role_label})")
219+
end
220+
parts << tag.div(
221+
class: "topic-icon-hover",
222+
data: { hover_popover_target: "popover", action: "mouseenter->hover-popover#show mouseleave->hover-popover#scheduleHide" }
223+
) { safe_join(hover_rows) }
224+
end
225+
226+
safe_join(parts)
227+
end
228+
end
229+
end

app/views/topics/_avatar_list.slim

Lines changed: 0 additions & 25 deletions
This file was deleted.

app/views/topics/_note_icon.html.slim

Lines changed: 0 additions & 8 deletions
This file was deleted.

app/views/topics/_participant_row.html.slim

Lines changed: 0 additions & 38 deletions
This file was deleted.

app/views/topics/_participation_icon.html.slim

Lines changed: 0 additions & 15 deletions
This file was deleted.

app/views/topics/_star_icon.html.slim

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)