From 9a61a7882d3c6aeff41dff3ca6e3fdf5e9832684 Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Mon, 8 Jun 2026 13:38:07 +0200 Subject: [PATCH 1/6] Bug 1764713 - Easily switch between open/closed/both combined bugs in bug search list --- buglist.cgi | 31 +++++++++++++++++++++ skins/standard/buglist.css | 37 +++++++++++++++++++++++++ template/en/default/list/list.html.tmpl | 26 +++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/buglist.cgi b/buglist.cgi index de17c06e30..cc6573d717 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -887,6 +887,35 @@ $vars->{'displaycolumns'} = \@displaycolumns; $vars->{'openstates'} = [BUG_STATE_OPEN]; $vars->{'closedstates'} = [map { $_->name } closed_bug_statuses()]; +# Determine which status filter tab is active for the toggle UI. +{ + my @requested = $cgi->param('bug_status'); + if (!@requested || grep { $_ eq '__all__' } @requested) { + $vars->{'status_filter'} = 'all'; + } + elsif (grep { $_ eq '__open__' } @requested) { + $vars->{'status_filter'} = 'open'; + } + elsif (grep { $_ eq '__closed__' } @requested) { + $vars->{'status_filter'} = 'closed'; + } + else { + my %open_set = map { $_ => 1 } BUG_STATE_OPEN; + my %closed_set = map { $_ => 1 } map { $_->name } closed_bug_statuses(); + my $has_open = grep { $open_set{$_} } @requested; + my $has_closed = grep { $closed_set{$_} } @requested; + if ($has_open && !$has_closed) { + $vars->{'status_filter'} = 'open'; + } + elsif ($has_closed && !$has_open) { + $vars->{'status_filter'} = 'closed'; + } + else { + $vars->{'status_filter'} = 'all'; + } + } +} + # The iCal file needs priorities ordered from 1 to 9 (highest to lowest) # If there are more than 9 values, just make all the lower ones 9 if ($format->{'extension'} eq 'ics') { @@ -1057,6 +1086,8 @@ else { # Set 'urlquerypart' once the buglist ID is known. $vars->{'urlquerypart'} = $params->canonicalize_query('order', 'cmdtype', 'query_based_on', 'token'); +$vars->{'urlquerypart_no_status'} + = $params->canonicalize_query('order', 'cmdtype', 'query_based_on', 'token', 'bug_status'); if ($format->{'extension'} eq "csv") { diff --git a/skins/standard/buglist.css b/skins/standard/buglist.css index 6f0ca67cb9..f286ffd749 100644 --- a/skins/standard/buglist.css +++ b/skins/standard/buglist.css @@ -9,6 +9,43 @@ text-align: center; } +.bz_status_toggle { + display: flex; + align-items: center; + gap: 4px; + margin: 8px 0; +} + +.bz_status_toggle_label { + color: var(--secondary-label-color); + font-size: var(--font-size-small); + margin-right: 4px; +} + +.bz_status_toggle_btn { + display: inline-block; + padding: 3px 12px; + border: 1px solid var(--secondary-region-border-color); + border-radius: 3px; + font-size: var(--font-size-small); + text-decoration: none; + color: var(--link-color); + background: transparent; + cursor: pointer; +} + +.bz_status_toggle_btn:hover { + background: var(--secondary-region-background-color); +} + +.bz_status_toggle_btn.active { + background: var(--link-color, #0060df); + color: #fff; + border-color: transparent; + cursor: default; + font-weight: 500; +} + .bz_query_head h1 { font-size: var(--font-size-h2); } diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl index c868898af9..aab1031b19 100644 --- a/template/en/default/list/list.html.tmpl +++ b/template/en/default/list/list.html.tmpl @@ -123,6 +123,32 @@
+[%############################################################################%] +[%# Status Filter Toggle #%] +[%############################################################################%] + +[% IF !dotweak %] + [% SET base_status_url = basepath _ "buglist.cgi?" _ urlquerypart_no_status %] +
+ Show: + [% IF status_filter == 'open' %] + Open + [% ELSE %] + Open + [% END %] + [% IF status_filter == 'closed' %] + Closed + [% ELSE %] + Closed + [% END %] + [% IF status_filter == 'all' %] + All + [% ELSE %] + All + [% END %] +
+[% END %] + [%############################################################################%] [%# Preceding Status Line #%] [%############################################################################%] From 928b4e9bb2b44e9e53c0c12f8e64e26226212ed3 Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Wed, 10 Jun 2026 17:55:34 +0200 Subject: [PATCH 2/6] Bug 1764713 - Fix non-existent CSS variable for proper theming and dark mode support --link-color is not defined anywhere in the codebase. The correct variable is --link-text-color (defined in global.css with a dark-mode variant). Also removes the hardcoded #0060df fallback on the active button background, which had poor contrast in dark mode --- skins/standard/buglist.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skins/standard/buglist.css b/skins/standard/buglist.css index f286ffd749..7480eab49f 100644 --- a/skins/standard/buglist.css +++ b/skins/standard/buglist.css @@ -29,7 +29,7 @@ border-radius: 3px; font-size: var(--font-size-small); text-decoration: none; - color: var(--link-color); + color: var(--link-text-color); background: transparent; cursor: pointer; } @@ -39,7 +39,7 @@ } .bz_status_toggle_btn.active { - background: var(--link-color, #0060df); + background: var(--link-text-color); color: #fff; border-color: transparent; cursor: default; From b58eac5f8f81f4fb29350f68fea4dacf6e067b3e Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Wed, 10 Jun 2026 18:15:58 +0200 Subject: [PATCH 3/6] Bug 1764713 - Use $params instead of $cgi for status filter detection For named/saved searches, $params is reassigned to a fresh Bugzilla::CGI($buffer) containing bug_status, while $cgi only holds the raw request params. So bug_status is empty there, causing the toggle to always show "All" active for saved searches --- buglist.cgi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buglist.cgi b/buglist.cgi index cc6573d717..43f3db44d2 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -889,7 +889,7 @@ $vars->{'closedstates'} = [map { $_->name } closed_bug_statuses()]; # Determine which status filter tab is active for the toggle UI. { - my @requested = $cgi->param('bug_status'); + my @requested = $params->param('bug_status'); if (!@requested || grep { $_ eq '__all__' } @requested) { $vars->{'status_filter'} = 'all'; } From f87ec895be707cbc16ea52b700453f5c55dc5b70 Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Wed, 10 Jun 2026 19:35:27 +0200 Subject: [PATCH 4/6] Bug 1764713 - Fix sort order preservation when clicking status toggle buttons Toggle links were missing &order=$qorder, silently dropping the user's custom sort when switching between Open/Closed/All. Consistent with all other navigation links in this template (e.g. "all search results", "Change Several Bugs at Once", and "Remember search" links) --- template/en/default/list/list.html.tmpl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/template/en/default/list/list.html.tmpl b/template/en/default/list/list.html.tmpl index aab1031b19..83bbefb11f 100644 --- a/template/en/default/list/list.html.tmpl +++ b/template/en/default/list/list.html.tmpl @@ -134,17 +134,17 @@ [% IF status_filter == 'open' %] Open [% ELSE %] - Open + Open [% END %] [% IF status_filter == 'closed' %] Closed [% ELSE %] - Closed + Closed [% END %] [% IF status_filter == 'all' %] All [% ELSE %] - All + All [% END %] [% END %] From 518a4ddec55c31a0b6b2dad5c304e02e8ecef4f0 Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Fri, 12 Jun 2026 12:52:30 +0200 Subject: [PATCH 5/6] Bug 1764713 - Replace boolean grep with List::Util::any to fix Perl::Critic violation --- buglist.cgi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/buglist.cgi b/buglist.cgi index 43f3db44d2..cc38c09c99 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -29,6 +29,7 @@ use Bugzilla::Status; use Bugzilla::Token; use Date::Parse; +use List::Util qw(any); use List::MoreUtils qw(uniq); @@ -890,13 +891,13 @@ $vars->{'closedstates'} = [map { $_->name } closed_bug_statuses()]; # Determine which status filter tab is active for the toggle UI. { my @requested = $params->param('bug_status'); - if (!@requested || grep { $_ eq '__all__' } @requested) { + if (!@requested || any { $_ eq '__all__' } @requested) { $vars->{'status_filter'} = 'all'; } - elsif (grep { $_ eq '__open__' } @requested) { + elsif (any { $_ eq '__open__' } @requested) { $vars->{'status_filter'} = 'open'; } - elsif (grep { $_ eq '__closed__' } @requested) { + elsif (any { $_ eq '__closed__' } @requested) { $vars->{'status_filter'} = 'closed'; } else { From 3f468e627aed98f6e1f7ea16992b1876e4838c9c Mon Sep 17 00:00:00 2001 From: Xavier L'Hour Date: Sat, 13 Jun 2026 12:39:02 +0200 Subject: [PATCH 6/6] Bug 1764713 - Exclude resolution from urlquerypart_no_status as it is coupled to bug_status --- buglist.cgi | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/buglist.cgi b/buglist.cgi index cc38c09c99..8356f97420 100755 --- a/buglist.cgi +++ b/buglist.cgi @@ -1087,8 +1087,11 @@ else { # Set 'urlquerypart' once the buglist ID is known. $vars->{'urlquerypart'} = $params->canonicalize_query('order', 'cmdtype', 'query_based_on', 'token'); +# Excludes resolution alongside bug_status from the query used by status toggle buttons. +# resolution is coupled to bug_status, so both must be dropped together $vars->{'urlquerypart_no_status'} - = $params->canonicalize_query('order', 'cmdtype', 'query_based_on', 'token', 'bug_status'); + = $params->canonicalize_query('order', 'cmdtype', 'query_based_on', 'token', + 'bug_status', 'resolution'); if ($format->{'extension'} eq "csv") {