Skip to content

Commit d51cc25

Browse files
committed
Introduce specific slots for sort and group quick filters to ensure the order is enforced
1 parent e862279 commit d51cc25

5 files changed

Lines changed: 102 additions & 6 deletions

File tree

.changeset/empty-poets-occur.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@openproject/primer-view-components': minor
3+
---
4+
5+
Introduce specific slots for sort and group quick filters

app/components/primer/open_project/sub_header.html.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
<%= render @collapsed_filter_trigger if @collapsed_filter_trigger.present? %>
99

10+
<%= sort_quick_filter %>
11+
<%= group_quick_filter %>
1012
<% quick_filters.each do |quick_filter| %>
1113
<%= quick_filter %>
1214
<% end %>

app/components/primer/open_project/sub_header.rb

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,27 @@ class SubHeader < Primer::Component
170170
}
171171
}
172172

173-
# Quick filters shown in the left pane next to the search bar (0–5 items).
174-
# Hidden on smaller screens. Requires all_filters_button to be set when used.
173+
# Quick filters shown in the left pane next to the search bar (0–5 items total across all types).
174+
# Hidden on smaller screens when more than one `quick_filter` is provided. Requires `filter_button` when using more than one `quick_filter`.
175175
# Supports ActionMenus, Buttons, IconButtons, SelectPanels, and SegmentedControls inside the block.
176+
#
177+
# Use `with_sort_quick_filter` for sort controls (renders first),
178+
# `with_group_quick_filter` for group controls (renders second),
179+
# and `with_quick_filter` for all others (renders last).
180+
renders_one :sort_quick_filter, lambda { |**kwargs|
181+
deny_tag_argument(**kwargs)
182+
kwargs[:tag] = :div
183+
kwargs[:mr] ||= 2
184+
QuickFilter.new(**kwargs)
185+
}
186+
187+
renders_one :group_quick_filter, lambda { |**kwargs|
188+
deny_tag_argument(**kwargs)
189+
kwargs[:tag] = :div
190+
kwargs[:mr] ||= 2
191+
QuickFilter.new(**kwargs)
192+
}
193+
176194
renders_many :quick_filters, lambda { |**kwargs|
177195
deny_tag_argument(**kwargs)
178196
kwargs[:tag] = :div
@@ -238,12 +256,14 @@ def initialize(collapsed_search: false, **system_arguments)
238256
end
239257

240258
def before_render
259+
all_qf = [sort_quick_filter, group_quick_filter].compact + quick_filters
260+
241261
if quick_filters.size > 1 && filter_button.nil?
242262
raise ArgumentError, "You must provide a filter_button when using quick_filters."
243263
end
244264

245-
if quick_filters.size > 5
246-
raise ArgumentError, "SubHeader supports a maximum of 5 quick_filters, got #{quick_filters.size}."
265+
if all_qf.size > 5
266+
raise ArgumentError, "SubHeader supports a maximum of 5 quick_filters, got #{all_qf.size}."
247267
end
248268

249269
if quick_filters.size > 1
@@ -254,7 +274,7 @@ def before_render
254274

255275
@system_arguments[:classes] = class_names(
256276
@system_arguments[:classes],
257-
"SubHeader--emptyLeftPane" => !segmented_control? && !filter_button && !filter_input && quick_filters.empty?
277+
"SubHeader--emptyLeftPane" => !segmented_control? && !filter_button && !filter_input && all_qf.empty?
258278
)
259279
end
260280

previews/primer/open_project/sub_header_preview/quick_filters.html.erb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@
55
"All filters"
66
end
77

8+
component.with_sort_quick_filter do
9+
render(Primer::Beta::IconButton.new(icon: :"sort-desc", "aria-label": "Sort"))
10+
end
11+
12+
component.with_group_quick_filter do
13+
render(Primer::Beta::IconButton.new(icon: :rows, "aria-label": "Group"))
14+
end
15+
816
component.with_quick_filter do
917
render(Primer::Alpha::SegmentedControl.new("aria-label": "File view")) do |component|
1018
component.with_item(label: "Monthly", selected: true)

test/components/primer/open_project/sub_header_test.rb

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,6 @@ def test_quick_filters_require_filter_button_when_multiple_quick_filters
304304
assert_equal "You must provide a filter_button when using quick_filters.", err.message
305305
end
306306

307-
308307
def test_quick_filters_require_no_filter_button_for_single_quick_filter
309308
render_inline(Primer::OpenProject::SubHeader.new) do |component|
310309
component.with_quick_filter { "<span class='MyQuickFilter'>Status</span>".html_safe }
@@ -323,4 +322,66 @@ def test_quick_filters_maximum_is_five
323322

324323
assert_equal "SubHeader supports a maximum of 5 quick_filters, got 6.", err.message
325324
end
325+
326+
def test_renders_sort_quick_filter
327+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
328+
component.with_sort_quick_filter { "<span class='SortFilter'>Sort</span>".html_safe }
329+
end
330+
331+
assert_selector(".SubHeader-leftPane .SortFilter")
332+
end
333+
334+
def test_renders_group_quick_filter
335+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
336+
component.with_group_quick_filter { "<span class='GroupFilter'>Group</span>".html_safe }
337+
end
338+
339+
assert_selector(".SubHeader-leftPane .GroupFilter")
340+
end
341+
342+
def test_sort_and_group_quick_filters_render_before_other_quick_filters
343+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
344+
component.with_filter_button { "Filter" }
345+
component.with_quick_filter(classes: "OtherFilter") { "Other" }
346+
component.with_group_quick_filter(classes: "GroupFilter") { "Group" }
347+
component.with_sort_quick_filter(classes: "SortFilter") { "Sort" }
348+
end
349+
350+
assert_selector(".SortFilter ~ .GroupFilter")
351+
assert_selector(".GroupFilter ~ .OtherFilter")
352+
end
353+
354+
def test_sort_and_group_do_not_count_toward_filter_button_requirement
355+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
356+
component.with_sort_quick_filter { "Sort" }
357+
component.with_quick_filter { "Status" }
358+
end
359+
360+
assert_text "Sort"
361+
assert_text "Status"
362+
end
363+
364+
def test_sort_and_group_count_toward_maximum
365+
err = assert_raises ArgumentError do
366+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
367+
component.with_filter_button { "Filter" }
368+
component.with_sort_quick_filter { "Sort" }
369+
component.with_group_quick_filter { "Group" }
370+
4.times { |i| component.with_quick_filter { "Filter #{i}" } }
371+
end
372+
end
373+
374+
assert_equal "SubHeader supports a maximum of 5 quick_filters, got 6.", err.message
375+
end
376+
377+
def test_sort_and_group_are_not_hidden_on_mobile_when_multiple_quick_filters
378+
render_inline(Primer::OpenProject::SubHeader.new) do |component|
379+
component.with_filter_button { "Filter" }
380+
component.with_sort_quick_filter { "<span class='SortFilter'>Sort</span>".html_safe }
381+
component.with_group_quick_filter { "<span class='GroupFilter'>Group</span>".html_safe }
382+
end
383+
384+
assert_no_selector(".d-none.d-md-flex .SortFilter")
385+
assert_no_selector(".d-none.d-md-flex .GroupFilter")
386+
end
326387
end

0 commit comments

Comments
 (0)