From d12cc757ab8fa062f48cc2ef92a3ea741e095502 Mon Sep 17 00:00:00 2001 From: Matt D'Angelo Date: Mon, 20 Oct 2025 14:26:38 +1030 Subject: [PATCH 1/2] Redirect to consolidated list when FF is enabled --- app/controllers/groups_controller.rb | 7 +++++++ ee/app/controllers/groups/epics_controller.rb | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 45911484281f5f..ef37051ebd8126 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -402,6 +402,13 @@ def destroy_immediately # Overridden in EE def redirect_if_epic_params; end + + def redirect_issues_to_work_items + return unless html_request? && ::Feature.enabled?(:work_item_planning_view, group) + + params = request.query_parameters.except("type").merge('type[]' => 'issue') + redirect_to group_work_items_path(group, params: params) + end end GroupsController.prepend_mod diff --git a/ee/app/controllers/groups/epics_controller.rb b/ee/app/controllers/groups/epics_controller.rb index 8bea091d54dbde..288ff49fcd66f1 100644 --- a/ee/app/controllers/groups/epics_controller.rb +++ b/ee/app/controllers/groups/epics_controller.rb @@ -15,6 +15,7 @@ class Groups::EpicsController < Groups::ApplicationController before_action :verify_group_bulk_edit_enabled!, only: [:bulk_update] before_action :set_summarize_notes_feature_flag, only: :show before_action :enforce_work_item_epics_feature_flags, only: [:new, :show] + before_action :redirect_epics_to_work_items, only: :index after_action :log_epic_show, only: :show before_action do @@ -141,4 +142,11 @@ def enforce_work_item_epics_feature_flags def set_summarize_notes_feature_flag push_force_frontend_feature_flag(:summarize_comments, can?(current_user, :summarize_comments, epic)) end + + def redirect_epics_to_work_items + return unless html_request? && ::Feature.enabled?(:work_item_planning_view, group) + + params = request.query_parameters.except("type").merge('type[]' => 'epic') + redirect_to group_work_items_path(group, params: params) + end end -- GitLab From 8a0ec939bc0cc61b2dc1c23765871f1b878474c7 Mon Sep 17 00:00:00 2001 From: Daniyal Arshad Date: Mon, 27 Oct 2025 20:43:05 +0500 Subject: [PATCH 2/2] Refactor redirect logic + add specs --- app/controllers/groups_controller.rb | 13 ++-- ee/app/controllers/ee/groups_controller.rb | 9 +++ ee/app/controllers/groups/epics_controller.rb | 7 +- .../controllers/ee/groups_controller_spec.rb | 67 ++++++++++++++++--- .../groups/epics_controller_spec.rb | 36 +++++++++- .../epics/epic_work_item_sync_spec.rb | 1 + .../list/user_bulk_edits_work_items_spec.rb | 2 + spec/controllers/groups_controller_spec.rb | 31 +++++++++ spec/features/groups/issues_spec.rb | 6 ++ .../new/user_creates_work_item_spec.rb | 1 + 10 files changed, 151 insertions(+), 22 deletions(-) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index ef37051ebd8126..14eb0fa95dc730 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -277,12 +277,14 @@ def unfoldered_environment_names end def issues - return if redirect_if_epic_params - return super unless html_request? set_sort_order + return redirect_issues_to_work_items if group&.work_items_consolidated_list_enabled?(current_user) + + return if redirect_if_epic_params + respond_to do |format| format.html end @@ -404,11 +406,14 @@ def destroy_immediately def redirect_if_epic_params; end def redirect_issues_to_work_items - return unless html_request? && ::Feature.enabled?(:work_item_planning_view, group) + params = work_items_redirect_params.except("type", "type[]").merge('type[]' => 'issue') - params = request.query_parameters.except("type").merge('type[]' => 'issue') redirect_to group_work_items_path(group, params: params) end + + def work_items_redirect_params + request.query_parameters + end end GroupsController.prepend_mod diff --git a/ee/app/controllers/ee/groups_controller.rb b/ee/app/controllers/ee/groups_controller.rb index 95a4c386adb09f..40797381546458 100644 --- a/ee/app/controllers/ee/groups_controller.rb +++ b/ee/app/controllers/ee/groups_controller.rb @@ -99,5 +99,14 @@ def redirect_if_epic_params true end + + override :work_items_redirect_params + def work_items_redirect_params + if has_epic_filter? + convert_epic_params + else + super + end + end end end diff --git a/ee/app/controllers/groups/epics_controller.rb b/ee/app/controllers/groups/epics_controller.rb index 288ff49fcd66f1..a4947be8c83f71 100644 --- a/ee/app/controllers/groups/epics_controller.rb +++ b/ee/app/controllers/groups/epics_controller.rb @@ -15,7 +15,6 @@ class Groups::EpicsController < Groups::ApplicationController before_action :verify_group_bulk_edit_enabled!, only: [:bulk_update] before_action :set_summarize_notes_feature_flag, only: :show before_action :enforce_work_item_epics_feature_flags, only: [:new, :show] - before_action :redirect_epics_to_work_items, only: :index after_action :log_epic_show, only: :show before_action do @@ -50,6 +49,8 @@ def new end def index + return redirect_epics_to_work_items if group&.work_items_consolidated_list_enabled?(current_user) + render 'work_items_index' end @@ -144,9 +145,7 @@ def set_summarize_notes_feature_flag end def redirect_epics_to_work_items - return unless html_request? && ::Feature.enabled?(:work_item_planning_view, group) - - params = request.query_parameters.except("type").merge('type[]' => 'epic') + params = request.query_parameters.except("type", "type[]").merge('type[]' => 'epic') redirect_to group_work_items_path(group, params: params) end end diff --git a/ee/spec/controllers/ee/groups_controller_spec.rb b/ee/spec/controllers/ee/groups_controller_spec.rb index f8f152255f9b4d..1e009ba7805981 100644 --- a/ee/spec/controllers/ee/groups_controller_spec.rb +++ b/ee/spec/controllers/ee/groups_controller_spec.rb @@ -627,22 +627,67 @@ def request(visibility_level) group.add_developer(user) end - it 'rewrites the epic_id param' do - get :issues, params: { id: group.to_param, epic_id: epic.id } - expect(response).to redirect_to issues_group_path(group, params: { parent_id: epic.work_item.id }) + shared_examples 'epic parameter redirect' do |redirect_path| + it 'redirects with epic_wildcard_id converted to parent_wildcard_id' do + get :issues, params: { id: group.to_param, epic_wildcard_id: 'ANY' } - get :issues, params: { id: group.to_param, epic_id: 'NONE' } - expect(response).to redirect_to issues_group_path(group, params: { parent_id: 'NONE' }) + expected_params = { parent_wildcard_id: 'ANY' } + expected_params['type[]'] = 'issue' if redirect_path == :group_work_items_path + + expect(response).to redirect_to send(redirect_path, group, params: expected_params) + end + + it 'redirects with epic_id converted to parent_id' do + get :issues, params: { id: group.to_param, epic_id: epic.id } + + expected_params = { parent_id: epic.work_item.id } + expected_params['type[]'] = 'issue' if redirect_path == :group_work_items_path + + expect(response).to redirect_to send(redirect_path, group, params: expected_params) + end + + it 'redirects with epic_id NONE converted to parent_id NONE' do + get :issues, params: { id: group.to_param, epic_id: 'NONE' } + + expected_params = { parent_id: 'NONE' } + expected_params['type[]'] = 'issue' if redirect_path == :group_work_items_path + + expect(response).to redirect_to send(redirect_path, group, params: expected_params) + end + + it 'redirects with not epic_id converted to not parent_id' do + get :issues, params: { id: group.to_param, not: { epic_id: epic.id } } + + expected_params = { not: { parent_id: epic.work_item.id } } + expected_params['type[]'] = 'issue' if redirect_path == :group_work_items_path + + expect(response).to redirect_to send(redirect_path, group, params: expected_params) + end + + it 'preserves other query parameters when redirecting with epic params' do + get :issues, params: { id: group.to_param, epic_wildcard_id: 'ANY', search: 'bug', sort: 'created_desc' } + + expected_params = { + parent_wildcard_id: 'ANY', + search: 'bug', + sort: 'created_desc' + } + expected_params['type[]'] = 'issue' if redirect_path == :group_work_items_path + + expect(response).to redirect_to send(redirect_path, group, params: expected_params) + end end - it 'rewrites the not epic_id param' do - get :issues, params: { id: group.to_param, not: { epic_id: epic.id } } - expect(response).to redirect_to issues_group_path(group, params: { not: { parent_id: epic.work_item.id } }) + context 'when work_item_planning_view feature flag is disabled' do + before do + stub_feature_flags(work_item_planning_view: false) + end + + it_behaves_like 'epic parameter redirect', :issues_group_path end - it 'rewrites the epic_wildcard_id param' do - get :issues, params: { id: group.to_param, epic_wildcard_id: 'ANY' } - expect(response).to redirect_to issues_group_path(group, params: { parent_wildcard_id: 'ANY' }) + context 'when work_item_planning_view feature flag is enabled' do + it_behaves_like 'epic parameter redirect', :group_work_items_path end end end diff --git a/ee/spec/controllers/groups/epics_controller_spec.rb b/ee/spec/controllers/groups/epics_controller_spec.rb index 88b74bf7d7c531..fcf14a494a26b8 100644 --- a/ee/spec/controllers/groups/epics_controller_spec.rb +++ b/ee/spec/controllers/groups/epics_controller_spec.rb @@ -61,10 +61,40 @@ group.add_developer(user) end - it "returns index" do - get :index, params: { group_id: group } + shared_examples 'epics index redirect' do |redirect_path, should_redirect| + if should_redirect + it 'redirects to work items path with epic type filter' do + get :index, params: { group_id: group } - expect(response).to have_gitlab_http_status(:ok) + expect(response).to redirect_to send(redirect_path, group, params: { 'type[]' => 'epic' }) + end + + it 'preserves query parameters except type when redirecting' do + get :index, params: { group_id: group, search: 'feature', sort: 'created_desc', type: 'old_type' } + + expect(response).to redirect_to send(redirect_path, group, + params: { search: 'feature', sort: 'created_desc', 'type[]' => 'epic' }) + end + else + it "renders the epics index page" do + get :index, params: { group_id: group } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template 'work_items_index' + end + end + end + + context 'when work_item_planning_view feature flag is enabled' do + it_behaves_like 'epics index redirect', :group_work_items_path, true + end + + context 'when work_item_planning_view feature flag is disabled' do + before do + stub_feature_flags(work_item_planning_view: false) + end + + it_behaves_like 'epics index redirect', :group_epics_path, false end end diff --git a/ee/spec/features/work_items/epics/epic_work_item_sync_spec.rb b/ee/spec/features/work_items/epics/epic_work_item_sync_spec.rb index 0abbc1b6d21d33..d0875c89158bad 100644 --- a/ee/spec/features/work_items/epics/epic_work_item_sync_spec.rb +++ b/ee/spec/features/work_items/epics/epic_work_item_sync_spec.rb @@ -31,6 +31,7 @@ describe 'from work item to epic' do before do + stub_feature_flags(work_item_planning_view: false) # TODO: remove threshold after epic-work item sync # issue: https://gitlab.com/gitlab-org/gitlab/-/issues/438295 allow(Gitlab::QueryLimiting::Transaction).to receive(:threshold).and_return(130) diff --git a/ee/spec/features/work_items/list/user_bulk_edits_work_items_spec.rb b/ee/spec/features/work_items/list/user_bulk_edits_work_items_spec.rb index d66837ccc6dc0d..6ed671ce904c9b 100644 --- a/ee/spec/features/work_items/list/user_bulk_edits_work_items_spec.rb +++ b/ee/spec/features/work_items/list/user_bulk_edits_work_items_spec.rb @@ -93,6 +93,7 @@ context 'when bulk editing parent on group issue list' do before do + stub_feature_flags(work_item_planning_view: false) allow(Gitlab::QueryLimiting).to receive(:threshold).and_return(132) visit issues_group_path(group) @@ -201,6 +202,7 @@ let_it_be(:child_epic_2) { create(:work_item, :epic, namespace: group, title: "Child epic 2") } before do + stub_feature_flags(work_item_planning_view: false) visit group_epics_path(group) click_bulk_edit end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 598a845ed59b3b..d89aff2af9c080 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -529,6 +529,33 @@ expect(user.reload.user_preference.issues_sort).to eq('priority') end + + context 'when work_item_planning_view feature flag is enabled' do + it 'redirects to work items path with issue type filter' do + get :issues, params: { id: group.to_param } + + expect(response).to redirect_to(group_work_items_path(group, params: { 'type[]' => 'issue' })) + end + + it 'preserves query parameters except type when redirecting' do + get :issues, params: { id: group.to_param, search: 'bug', sort: 'created_desc', type: 'old_type' } + + expect(response).to redirect_to(group_work_items_path(group, params: { search: 'bug', sort: 'created_desc', 'type[]' => 'issue' })) + end + end + + context 'when work_item_planning_view feature flag is disabled' do + before do + stub_feature_flags(work_item_planning_view: false) + end + + it 'renders the issues page' do + get :issues, params: { id: group.to_param } + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template 'groups/issues' + end + end end describe 'GET #merge_requests', :sidekiq_might_not_need_inline do @@ -1568,6 +1595,10 @@ def get_activity end describe 'GET #issues' do + before do + stub_feature_flags(work_item_planning_view: false) + end + subject { get :issues, params: { id: group.to_param } } it_behaves_like 'disabled when using an external authorization service' diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index 1647078118fd44..59955e0b391bca 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -15,6 +15,10 @@ context 'with shared examples', :js do let(:issuable) { create(:issue, project: project, title: "this is my created issuable") } + before do + stub_feature_flags(work_item_planning_view: false) + end + include_examples 'project features apply to issuables', Issue context 'rss feed' do @@ -92,6 +96,7 @@ let!(:subgroup_issue) { create(:issue, project: subgroup_project) } before do + stub_feature_flags(work_item_planning_view: false) visit issues_group_path(group_with_no_issues) end @@ -105,6 +110,7 @@ let(:user_in_group) { create(:group_member, :maintainer, user: create(:user), group: group).user } before do + stub_feature_flags(work_item_planning_view: false) [project, project_with_issues_disabled].each { |project| project.add_maintainer(user_in_group) } sign_in(user_in_group) visit issues_group_path(group) diff --git a/spec/features/work_items/new/user_creates_work_item_spec.rb b/spec/features/work_items/new/user_creates_work_item_spec.rb index a468a807d0fad1..498e4a811ea862 100644 --- a/spec/features/work_items/new/user_creates_work_item_spec.rb +++ b/spec/features/work_items/new/user_creates_work_item_spec.rb @@ -91,6 +91,7 @@ let_it_be(:project_with_issues_disabled) { create(:project, :issues_disabled, group: group) } before do + stub_feature_flags(work_item_planning_view: false) [project, project_with_issues_disabled].each { |project| project.add_maintainer(user_in_group) } sign_in(user_in_group) visit issues_group_path(group) -- GitLab