diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index 3708c885143701ae7279aa6219b384f77d9f226e..2300687ed4c031c1342447f0c70853ac9beed137 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -36,6 +36,7 @@ class ApplicationSettingsController < Admin::ApplicationController feature_category :integrations, [:integrations, :slack_app_manifest_share, :slack_app_manifest_download] feature_category :pages, [:lets_encrypt_terms_of_service] feature_category :observability, [:reset_error_tracking_access_token] + feature_category :global_search, [:search] VALID_SETTING_PANELS = %w[general repository ci_cd reporting metrics_and_profiling diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 6b8cd2b029ee2117ade4022f7d2dada5c3c20150..75741f2d4a24fe75d0a8c5d3ea46ddf9023da47e 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -72,6 +72,31 @@ def enabled_protocol_button(container, protocol) end end + def global_search_settings_checkboxes(form) + [ + form.gitlab_ui_checkbox_component( + :global_search_issues_enabled, + _("Enable issues tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_issues_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_merge_requests_enabled, + _("Enable merge requests tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_merge_requests_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_snippet_titles_enabled, + _("Enable snippet tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_snippet_titles_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_users_enabled, + _("Enable users tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_users_enabled, multiple: false } + ) + ] + end + def restricted_level_checkboxes(form) restricted_visibility_levels_help_text = { Gitlab::VisibilityLevel::PUBLIC => s_( @@ -544,7 +569,11 @@ def visible_attributes :require_personal_access_token_expiry, :observability_backend_ssl_verification_enabled, :show_migrate_from_jenkins_banner, - :ropc_without_client_credentials + :ropc_without_client_credentials, + :global_search_snippet_titles_enabled, + :global_search_users_enabled, + :global_search_issues_enabled, + :global_search_merge_requests_enabled ].tap do |settings| unless Gitlab.com? settings << :resource_usage_limits diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 197313c3ff90a3e0f9f6826d0360bb90978287cf..b58bead78d69ef1853bb41023624c9a37a6a0a63 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -428,7 +428,7 @@ def projects_autocomplete(term, limit = 5) def users_autocomplete(term, limit = 5) unless current_user && Ability.allowed?(current_user, :read_users_list) && - Feature.enabled?(:global_search_users_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_users_enabled? return [] end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 906492003ac81dfc68d84e3aa872d7c72e44709c..a61788818a8230e179b11fa94000dc352ad2fa3f 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -105,17 +105,17 @@ def level end def global_search_enabled_for_scope? - return false if show_snippets? && Feature.disabled?(:global_search_snippet_titles_tab, current_user, type: :ops) + return false if show_snippets? && !::Gitlab::CurrentSettings.global_search_snippet_titles_enabled? case params[:scope] when 'issues' - Feature.enabled?(:global_search_issues_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_issues_enabled? when 'merge_requests' - Feature.enabled?(:global_search_merge_requests_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_merge_requests_enabled? when 'snippet_titles' - Feature.enabled?(:global_search_snippet_titles_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_snippet_titles_enabled? when 'users' - Feature.enabled?(:global_search_users_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_users_enabled? else true end diff --git a/app/views/admin/application_settings/_global_search_settings.html.haml b/app/views/admin/application_settings/_global_search_settings.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..185bc4035b3b168c5523b30ba075a99fe365c308 --- /dev/null +++ b/app/views/admin/application_settings/_global_search_settings.html.haml @@ -0,0 +1,15 @@ += render ::Layouts::SettingsBlockComponent.new(_('Global Search'), + id: 'js-global-search-settings', + testid: 'admin-global-search-settings', + expanded: expanded_by_default?) do |c| + - c.with_description do + = _('Configure settings for global search.') + = link_to _('Learn more.'), help_page_path('user/search/index.md', anchor: 'global-search-scopes'), target: '_blank', rel: 'noopener noreferrer' + - c.with_body do + = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-global-search-settings'), html: { class: 'fieldset-form', id: 'global-search-settings' } do |f| + = form_errors(@application_setting) + %fieldset + .form-group + - global_search_settings_checkboxes(f).each do |checkbox| + = checkbox + = f.submit _('Save changes'), pajamas_button: true diff --git a/app/views/admin/application_settings/search.html.haml b/app/views/admin/application_settings/search.html.haml new file mode 100644 index 0000000000000000000000000000000000000000..1e6cd122190961bfa23e89f7823b63650a53d44e --- /dev/null +++ b/app/views/admin/application_settings/search.html.haml @@ -0,0 +1,7 @@ +- breadcrumb_title _("Search") +- page_title _("Search") +- add_page_specific_style 'page_bundles/settings' +- add_page_specific_style 'page_bundles/search' +- @force_desktop_expanded_sidebar = true + += render 'admin/application_settings/global_search_settings' diff --git a/config/routes/admin.rb b/config/routes/admin.rb index c54397860e60a4b6459ef33f0ab7693e0ccc6c7d..a00f316e85cd0d3afe67274229bcf430a8f86949 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -168,7 +168,7 @@ put :reset_health_check_token put :reset_error_tracking_access_token put :clear_repository_check_states - match :general, :integrations, :repository, :ci_cd, :reporting, :metrics_and_profiling, :network, :preferences, via: [:get, :patch] + match :general, :integrations, :repository, :ci_cd, :reporting, :metrics_and_profiling, :network, :preferences, :search, via: [:get, :patch] get :lets_encrypt_terms_of_service get :slack_app_manifest_download, format: :json get :slack_app_manifest_share diff --git a/db/migrate/20250109055316_migrate_global_search_settings_in_application_settings.rb b/db/migrate/20250109055316_migrate_global_search_settings_in_application_settings.rb new file mode 100644 index 0000000000000000000000000000000000000000..aff522460c2ad088d34a61eae9194f5c07240435 --- /dev/null +++ b/db/migrate/20250109055316_migrate_global_search_settings_in_application_settings.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +class MigrateGlobalSearchSettingsInApplicationSettings < Gitlab::Database::Migration[2.2] + restrict_gitlab_migration gitlab_schema: :gitlab_main + milestone '17.9' + + class ApplicationSetting < MigrationRecord + self.table_name = 'application_settings' + end + + def up + ApplicationSetting.reset_column_information + + application_setting = ApplicationSetting.last + return unless application_setting + + # rubocop:disable Gitlab/FeatureFlagWithoutActor -- Does not execute in user context + search = { + global_search_issues_enabled: Feature.enabled?(:global_search_issues_tab, type: :ops), + global_search_merge_requests_enabled: Feature.enabled?(:global_search_merge_requests_tab, type: :ops), + global_search_snippet_titles_enabled: Feature.enabled?(:global_search_snippet_titles_tab, type: :ops), + global_search_users_enabled: Feature.enabled?(:global_search_users_tab, type: :ops) + } + + if Gitlab.ee? + search.merge!( + global_search_code_enabled: Feature.enabled?(:global_search_code_tab, type: :ops), + global_search_commits_enabled: Feature.enabled?(:global_search_commits_tab, type: :ops), + global_search_epics_enabled: Feature.enabled?(:global_search_epics_tab, type: :ops), + global_search_wiki_enabled: Feature.enabled?(:global_search_wiki_tab, type: :ops) + ) + end + # rubocop:enable Gitlab/FeatureFlagWithoutActor + + application_setting.update_columns(search: search, updated_at: Time.current) + end + + def down + application_setting = ApplicationSetting.last + return unless application_setting + + application_setting.update_column(:search, {}) + end +end diff --git a/db/schema_migrations/20250109055316 b/db/schema_migrations/20250109055316 new file mode 100644 index 0000000000000000000000000000000000000000..5b6db794f915a7fb301ac058619c3a631874ce0e --- /dev/null +++ b/db/schema_migrations/20250109055316 @@ -0,0 +1 @@ +213fa997d255628cb8f3e3fc6b2098e8fded40aa2eae7593ac5b123b08ff72d8 \ No newline at end of file diff --git a/ee/app/helpers/ee/application_settings_helper.rb b/ee/app/helpers/ee/application_settings_helper.rb index 33b4c93c063d5b162a8c27c9fe7effd200435094..155810e3b477581eef89468155c0f5ff2b124a6a 100644 --- a/ee/app/helpers/ee/application_settings_helper.rb +++ b/ee/app/helpers/ee/application_settings_helper.rb @@ -88,7 +88,11 @@ def visible_attributes :scan_execution_policies_action_limit, :secret_detection_service_auth_token, :secret_detection_service_url, - :fetch_observability_alerts_from_cloud + :fetch_observability_alerts_from_cloud, + :global_search_code_enabled, + :global_search_commits_enabled, + :global_search_wiki_enabled, + :global_search_epics_enabled ].tap do |settings| settings.concat(identity_verification_attributes) settings.concat(enable_promotion_management_attributes) @@ -265,6 +269,32 @@ def sync_purl_types_checkboxes(form) end end + override :global_search_settings_checkboxes + def global_search_settings_checkboxes(form) + super + [ + form.gitlab_ui_checkbox_component( + :global_search_code_enabled, + _("Enable code tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_code_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_commits_enabled, + _("Enable commits tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_commits_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_epics_enabled, + _("Enable epics tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_epics_enabled, multiple: false } + ), + form.gitlab_ui_checkbox_component( + :global_search_wiki_enabled, + _("Enable wiki tab in global search results"), + checkbox_options: { checked: @application_setting.global_search_wiki_enabled, multiple: false } + ) + ] + end + def zoekt_settings_checkboxes(form) [ form.gitlab_ui_checkbox_component( diff --git a/ee/app/services/ee/search_service.rb b/ee/app/services/ee/search_service.rb index 83155952e691402a4b37d12474dd6bafbea72f74..26804e7864fb1dfe0d8deacea8d4d444d51f1061 100644 --- a/ee/app/services/ee/search_service.rb +++ b/ee/app/services/ee/search_service.rb @@ -45,13 +45,13 @@ def use_zoekt? def global_search_enabled_for_scope? case params[:scope] when 'blobs' - ::Feature.enabled?(:global_search_code_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_code_enabled? when 'commits' - ::Feature.enabled?(:global_search_commits_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_commits_enabled? when 'epics' - ::Feature.enabled?(:global_search_epics_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_epics_enabled? when 'wiki_blobs' - ::Feature.enabled?(:global_search_wiki_tab, current_user, type: :ops) + ::Gitlab::CurrentSettings.global_search_wiki_enabled? else super end diff --git a/ee/app/views/admin/application_settings/search.html.haml b/ee/app/views/admin/application_settings/search.html.haml index c23e51a0e747db6fa36c796b3687b1b37f8993af..1bf1155ca165e42221372948997c2dc57af4c003 100644 --- a/ee/app/views/admin/application_settings/search.html.haml +++ b/ee/app/views/admin/application_settings/search.html.haml @@ -49,5 +49,6 @@ - c.with_body do = s_('AdvancedSearch|You have %{count} pending %{migrations_link_start}advanced search migrations%{link_end} that are obsolete. These migrations might affect your search experience. To resolve the issue, you must %{recreate_link_start}recreate your index%{link_end}.').html_safe % { count: @elasticsearch_pending_obsolete_migrations.count, migrations_link_start: help_advanced_search_migrations_link_start, recreate_link_start: help_recreate_index_link_start, link_end: ''.html_safe } -= render_if_exists 'admin/application_settings/elasticsearch_form' -= render_if_exists 'admin/application_settings/zoekt_configuration_settings' if ::License.feature_available?(:zoekt_code_search) += render 'admin/application_settings/global_search_settings' += render 'admin/application_settings/elasticsearch_form' if License.feature_available?(:elastic_search) += render 'admin/application_settings/zoekt_configuration_settings' if ::License.feature_available?(:zoekt_code_search) diff --git a/ee/lib/ee/search/navigation.rb b/ee/lib/ee/search/navigation.rb index 7fc6ebf08a98a67bfafddb949d156d808091868e..8e0ec0bc2526ffc49b45fe6e1a384f03fd295abf 100644 --- a/ee/lib/ee/search/navigation.rb +++ b/ee/lib/ee/search/navigation.rb @@ -47,7 +47,7 @@ def show_code_search_tab? return true if super return false if project - global_search_code_enabled = ::Feature.enabled?(:global_search_code_tab, user, type: :ops) + global_search_code_enabled = ::Gitlab::CurrentSettings.global_search_code_enabled? global_search_zoekt_enabled = ::Feature.enabled?(:zoekt_cross_namespace_search, user, type: :ops) zoekt_enabled_for_user = zoekt_enabled? && ::Search::Zoekt.enabled_for_user?(user) @@ -72,7 +72,7 @@ def show_wiki_search_tab? return false unless show_elasticsearch_tabs? return true if group - ::Feature.enabled?(:global_search_wiki_tab, user, type: :ops) + ::Gitlab::CurrentSettings.global_search_wiki_enabled? end def show_epics_search_tab? @@ -80,7 +80,7 @@ def show_epics_search_tab? return false unless options[:show_epics] return true if group - ::Feature.enabled?(:global_search_epics_tab, user, type: :ops) + ::Gitlab::CurrentSettings.global_search_epics_enabled? end override :show_commits_search_tab? @@ -89,7 +89,7 @@ def show_commits_search_tab? return false unless show_elasticsearch_tabs? # advanced search enabled return true if group # group search - ::Feature.enabled?(:global_search_commits_tab, user, type: :ops) # global search + ::Gitlab::CurrentSettings.global_search_commits_enabled? end end end diff --git a/ee/lib/ee/sidebars/admin/menus/admin_settings_menu.rb b/ee/lib/ee/sidebars/admin/menus/admin_settings_menu.rb index 3e438cc1354bcb77c0f649ee00e23c46c681e1ac..4e573944cd2344e83fa7e8bfa33c1d7847e0a6fa 100644 --- a/ee/lib/ee/sidebars/admin/menus/admin_settings_menu.rb +++ b/ee/lib/ee/sidebars/admin/menus/admin_settings_menu.rb @@ -14,7 +14,6 @@ def configure_menu_items insert_item_after(:general_settings, service_accounts_menu_item) insert_item_after(:service_accounts, roles_and_permissions_menu_item) - insert_item_after(:roles_and_permissions, search_menu_item) insert_item_after(:admin_reporting, templates_menu_item) insert_item_after(:admin_ci_cd, security_and_compliance_menu_item) insert_item_after(:security_and_compliance_menu_item, analytics_menu_item) @@ -55,18 +54,6 @@ def service_accounts_available? !gitlab_com_subscription? end - def search_menu_item - return ::Sidebars::NilMenuItem.new(item_id: :search) unless ::License.feature_available?(:elastic_search) - - ::Sidebars::MenuItem.new( - title: _('Search'), - link: search_admin_application_settings_path, - active_routes: { path: 'admin/application_settings#search' }, - item_id: :search, - container_html_options: { testid: 'admin-settings-search-link' } - ) - end - def templates_menu_item unless ::License.feature_available?(:custom_file_templates) return ::Sidebars::NilMenuItem.new(item_id: :admin_templates) diff --git a/ee/spec/controllers/ee/search_controller_spec.rb b/ee/spec/controllers/ee/search_controller_spec.rb index 955c275c4ff98a14f0058e33712e71b413d05640..1c8ce453ca5c56ae055e419bb3feb7f7e16e29fd 100644 --- a/ee/spec/controllers/ee/search_controller_spec.rb +++ b/ee/spec/controllers/ee/search_controller_spec.rb @@ -203,15 +203,15 @@ subject(:show) { get :show, params: { scope: scope, search: 'term' }, format: :html } - where(:feature_flag, :scope) do - :global_search_code_tab | 'blobs' - :global_search_commits_tab | 'commits' - :global_search_wiki_tab | 'wiki_blobs' + where(:admin_setting, :scope) do + :global_search_code_enabled | 'blobs' + :global_search_commits_enabled | 'commits' + :global_search_wiki_enabled | 'wiki_blobs' end with_them do it 'returns 200 if flag is enabled' do - stub_feature_flags(feature_flag => true) + stub_application_setting(admin_setting => true) show @@ -219,7 +219,7 @@ end it 'redirects with alert if flag is disabled' do - stub_feature_flags(feature_flag => false) + stub_application_setting(admin_setting => false) show diff --git a/ee/spec/helpers/ee/application_settings_helper_spec.rb b/ee/spec/helpers/ee/application_settings_helper_spec.rb index 97a2a1ec6e003317fe09f78440e38a8bd6f25119..1326e987d2d37cfa5000a2809e02055d236a0d6e 100644 --- a/ee/spec/helpers/ee/application_settings_helper_spec.rb +++ b/ee/spec/helpers/ee/application_settings_helper_spec.rb @@ -13,6 +13,20 @@ expect(visible_attributes).to include(*%i[duo_features_enabled lock_duo_features_enabled duo_availability]) end + it 'contains search parameters' do + expected_fields = %i[ + global_search_code_enabled + global_search_commits_enabled + global_search_wiki_enabled + global_search_epics_enabled + global_search_snippet_titles_enabled + global_search_users_enabled + global_search_issues_enabled + global_search_merge_requests_enabled + ] + expect(helper.visible_attributes).to include(*expected_fields) + end + it 'contains zoekt parameters' do expected_fields = %i[ zoekt_auto_delete_lost_nodes zoekt_auto_index_root_namespace zoekt_indexing_enabled @@ -231,6 +245,36 @@ end end + describe '#global_search_settings_checkboxes', feature_category: :global_search do + let_it_be(:application_setting) { build(:application_setting) } + + before do + application_setting.global_search_issues_enabled = true + application_setting.global_search_merge_requests_enabled = false + application_setting.global_search_snippet_titles_enabled = true + application_setting.global_search_users_enabled = false + application_setting.global_search_code_enabled = true + application_setting.global_search_commits_enabled = false + application_setting.global_search_epics_enabled = true + application_setting.global_search_wiki_enabled = true + helper.instance_variable_set(:@application_setting, application_setting) + end + + it 'returns correctly checked checkboxes' do + helper.gitlab_ui_form_for(application_setting, url: search_admin_application_settings_path) do |form| + result = helper.global_search_settings_checkboxes(form) + expect(result[0]).to have_checked_field('Enable issues tab in global search results', with: 1) + expect(result[1]).not_to have_checked_field('Enable merge requests tab in global search results', with: 1) + expect(result[2]).to have_checked_field('Enable snippet tab in global search results', with: 1) + expect(result[3]).not_to have_checked_field('Enable users tab in global search results', with: 1) + expect(result[4]).to have_checked_field('Enable code tab in global search results', with: 1) + expect(result[5]).not_to have_checked_field('Enable commits tab in global search results', with: 1) + expect(result[6]).to have_checked_field('Enable epics tab in global search results', with: 1) + expect(result[7]).to have_checked_field('Enable wiki tab in global search results', with: 1) + end + end + end + describe '#zoekt_settings_checkboxes', feature_category: :global_search do let_it_be(:application_setting) { build(:application_setting) } diff --git a/ee/spec/lib/ee/sidebars/admin/menus/admin_settings_menu_spec.rb b/ee/spec/lib/ee/sidebars/admin/menus/admin_settings_menu_spec.rb index a6465ea33a1e8007e7312277a5ea890029292510..f18639e9a118259a36822596315babe25dad63d5 100644 --- a/ee/spec/lib/ee/sidebars/admin/menus/admin_settings_menu_spec.rb +++ b/ee/spec/lib/ee/sidebars/admin/menus/admin_settings_menu_spec.rb @@ -79,21 +79,7 @@ describe 'Search', feature_category: :global_search do let(:item_id) { :search } - context 'when elastic_search feature is not licensed' do - before do - stub_licensed_features(elastic_search: false) - end - - it { is_expected.not_to be_present } - end - - context 'when elastic_search feature is licensed' do - before do - stub_licensed_features(elastic_search: true) - end - - it { is_expected.to be_present } - end + it { is_expected.to be_present } end end end diff --git a/ee/spec/lib/search/navigation_spec.rb b/ee/spec/lib/search/navigation_spec.rb index 8f3eddb2716e1f59a4558aec7273de595a8fdc1e..9b79294c77cf32717085069be7e750afec27cf71 100644 --- a/ee/spec/lib/search/navigation_spec.rb +++ b/ee/spec/lib/search/navigation_spec.rb @@ -44,7 +44,7 @@ let(:project) { nil } let(:group) { group_double } - where(:feature_flag, :show_elasticsearch_tabs, :condition) do + where(:setting_enabled, :show_elasticsearch_tabs, :condition) do true | true | true true | false | false false | true | true @@ -55,7 +55,7 @@ let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } before do - stub_feature_flags(global_search_commits_tab: feature_flag) + stub_application_setting(global_search_commits_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -68,7 +68,7 @@ let(:project) { nil } let(:group) { nil } - where(:feature_flag, :show_elasticsearch_tabs, :condition) do + where(:setting_enabled, :show_elasticsearch_tabs, :condition) do true | true | true false | true | false false | false | false @@ -81,7 +81,7 @@ let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } before do - stub_feature_flags(global_search_commits_tab: feature_flag) + stub_application_setting(global_search_commits_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -95,7 +95,7 @@ context 'when project search' do let(:project) { project_double } - where(:feature_flag, :show_epics, :condition) do + where(:setting_enabled, :show_epics, :condition) do false | true | false false | false | false true | true | false @@ -106,7 +106,7 @@ let(:options) { { show_epics: show_epics } } it 'data item condition is set correctly' do - stub_feature_flags(global_search_epics_tab: feature_flag) + stub_application_setting(global_search_epics_enabled: setting_enabled) expect(tabs[:issues][:sub_items][:epic][:condition]).to eq(condition) end @@ -136,7 +136,7 @@ let(:project) { nil } let(:group) { nil } - where(:feature_flag, :show_epics, :condition) do + where(:setting_enabled, :show_epics, :condition) do false | false | false true | false | false false | true | false @@ -147,7 +147,7 @@ let(:options) { { show_epics: show_epics } } it 'data item condition is set correctly' do - stub_feature_flags(global_search_epics_tab: feature_flag) + stub_application_setting(global_search_epics_enabled: setting_enabled) expect(tabs[:issues][:sub_items][:epic][:condition]).to eq(condition) end @@ -180,7 +180,7 @@ let(:project) { nil } let(:group) { group_double } - where(:feature_flag, :show_elasticsearch_tabs, :condition) do + where(:setting_enabled, :show_elasticsearch_tabs, :condition) do true | true | true true | false | false false | true | true @@ -191,7 +191,7 @@ let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } before do - stub_feature_flags(global_search_wiki_tab: feature_flag) + stub_application_setting(global_search_wiki_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -204,7 +204,7 @@ let(:project) { nil } let(:group) { nil } - where(:feature_flag, :show_elasticsearch_tabs, :condition) do + where(:setting_enabled, :show_elasticsearch_tabs, :condition) do true | true | true false | true | false false | false | false @@ -217,7 +217,7 @@ let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs } } before do - stub_feature_flags(global_search_wiki_tab: feature_flag) + stub_application_setting(global_search_wiki_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -290,7 +290,7 @@ let(:project) { nil } let(:group) { nil } - where(:global_search_code_tab_enabled, :global_search_with_zoekt_enabled, :show_elasticsearch_tabs, + where(:global_search_code_enabled, :global_search_with_zoekt_enabled, :show_elasticsearch_tabs, :zoekt_enabled, :zoekt_enabled_for_user, :condition) do false | false | false | false | false | false false | false | false | false | true | false @@ -330,7 +330,7 @@ let(:options) { { show_elasticsearch_tabs: show_elasticsearch_tabs, zoekt_enabled: zoekt_enabled } } before do - stub_feature_flags(global_search_code_tab: global_search_code_tab_enabled) + stub_application_setting(global_search_code_enabled: global_search_code_enabled) stub_feature_flags(zoekt_cross_namespace_search: global_search_with_zoekt_enabled) allow(::Search::Zoekt).to receive(:enabled_for_user?).and_return(zoekt_enabled_for_user) end diff --git a/ee/spec/requests/api/graphql/search/blob_search_spec.rb b/ee/spec/requests/api/graphql/search/blob_search_spec.rb index d014eefd0d9572b0ae50d117467687e1c41c8f8b..cb9c69c64a94935d8e71e444c8c6816b4c2a7e23 100644 --- a/ee/spec/requests/api/graphql/search/blob_search_spec.rb +++ b/ee/spec/requests/api/graphql/search/blob_search_spec.rb @@ -58,7 +58,7 @@ context 'when global search is disabled for blobs' do before do - stub_feature_flags(global_search_code_tab: false) + stub_application_setting(global_search_code_enabled: false) end context 'when group_id and project_id not passed' do diff --git a/ee/spec/services/search_service_spec.rb b/ee/spec/services/search_service_spec.rb index b3367a6d9cb35e354a325b77684316354e344677..4f8c7f007f7a5f8790f011884ee3084ebb5f764c 100644 --- a/ee/spec/services/search_service_spec.rb +++ b/ee/spec/services/search_service_spec.rb @@ -109,20 +109,20 @@ let(:search_service) { described_class.new(user, { scope: scope, search: search }) } let(:search) { 'foobar' } - where(:scope, :feature_flag, :enabled, :expected) do - 'blobs' | :global_search_code_tab | false | false - 'blobs' | :global_search_code_tab | true | true - 'commits' | :global_search_commits_tab | false | false - 'commits' | :global_search_commits_tab | true | true - 'epics' | :global_search_epics_tab | false | false - 'epics' | :global_search_epics_tab | true | true - 'wiki_blobs' | :global_search_wiki_tab | false | false - 'wiki_blobs' | :global_search_wiki_tab | true | true + where(:scope, :admin_setting, :setting_enabled, :expected) do + 'blobs' | :global_search_code_enabled | false | false + 'blobs' | :global_search_code_enabled | true | true + 'commits' | :global_search_commits_enabled | false | false + 'commits' | :global_search_commits_enabled | true | true + 'epics' | :global_search_epics_enabled | false | false + 'epics' | :global_search_epics_enabled | true | true + 'wiki_blobs' | :global_search_wiki_enabled | false | false + 'wiki_blobs' | :global_search_wiki_enabled | true | true end with_them do it 'returns false when feature_flag is not enabled and returns true when feature_flag is enabled' do - stub_feature_flags(feature_flag => enabled) + stub_application_setting(admin_setting => setting_enabled) expect(search_service.global_search_enabled_for_scope?).to eq expected end end diff --git a/lib/search/navigation.rb b/lib/search/navigation.rb index 971b6f4ec801ca8b075e9c2194e2fb0c12ed403a..e0facef289a43006d5ec5d107469571bc4c641a1 100644 --- a/lib/search/navigation.rb +++ b/lib/search/navigation.rb @@ -127,7 +127,7 @@ def show_user_search_tab? return true if tab_enabled_for_project?(:users) return false unless can?(user, :read_users_list) - project.nil? && (group.present? || Feature.enabled?(:global_search_users_tab, user, type: :ops)) + project.nil? && (group.present? || ::Gitlab::CurrentSettings.global_search_users_enabled?) end def show_code_search_tab? @@ -145,13 +145,13 @@ def show_commits_search_tab? def show_issues_search_tab? return true if tab_enabled_for_project?(:issues) - project.nil? && (group.present? || Feature.enabled?(:global_search_issues_tab, user, type: :ops)) + project.nil? && (group.present? || ::Gitlab::CurrentSettings.global_search_issues_enabled?) end def show_merge_requests_search_tab? return true if tab_enabled_for_project?(:merge_requests) - project.nil? && (group.present? || Feature.enabled?(:global_search_merge_requests_tab, user, type: :ops)) + project.nil? && (group.present? || ::Gitlab::CurrentSettings.global_search_merge_requests_enabled?) end def show_comments_search_tab? @@ -162,7 +162,7 @@ def show_comments_search_tab? def show_snippets_search_tab? !!options[:show_snippets] && project.nil? && - (group.present? || Feature.enabled?(:global_search_snippet_titles_tab, user, type: :ops)) + (group.present? || ::Gitlab::CurrentSettings.global_search_snippet_titles_enabled?) end def show_milestones_search_tab? diff --git a/lib/sidebars/admin/menus/admin_settings_menu.rb b/lib/sidebars/admin/menus/admin_settings_menu.rb index bb9cedec9aa405f6e885abbcef385609fabc532e..ce55633d6414a5dcbb515e27cddb4da69a237e28 100644 --- a/lib/sidebars/admin/menus/admin_settings_menu.rb +++ b/lib/sidebars/admin/menus/admin_settings_menu.rb @@ -7,6 +7,7 @@ class AdminSettingsMenu < ::Sidebars::Admin::BaseMenu override :configure_menu_items def configure_menu_items add_item(general_settings_menu_item) + add_item(search_menu_item) add_item(integrations_menu_item) add_item(repository_menu_item) add_item(ci_cd_menu_item) @@ -51,6 +52,16 @@ def general_settings_menu_item ) end + def search_menu_item + ::Sidebars::MenuItem.new( + title: _('Search'), + link: search_admin_application_settings_path, + active_routes: { path: 'admin/application_settings#search' }, + item_id: :search, + container_html_options: { testid: 'admin-settings-search-link' } + ) + end + def integrations_menu_item return ::Sidebars::NilMenuItem.new(item_id: :admin_integrations) unless instance_level_integrations? diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d7d28d4d5264b7a83f0e5288da9bae5684c413e8..df6a2f592aaa09e5b6b6c24cade91867be02b3f4 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -15229,6 +15229,9 @@ msgstr "" msgid "Configure settings for exact code search." msgstr "" +msgid "Configure settings for global search." +msgstr "" + msgid "Configure specific limits for Files API requests that supersede the general user and IP rate limits." msgstr "" @@ -22069,12 +22072,21 @@ msgstr "" msgid "Enable cleanup policy caching." msgstr "" +msgid "Enable code tab in global search results" +msgstr "" + +msgid "Enable commits tab in global search results" +msgstr "" + msgid "Enable diagrams.net" msgstr "" msgid "Enable email notification" msgstr "" +msgid "Enable epics tab in global search results" +msgstr "" + msgid "Enable exact code search" msgstr "" @@ -22108,9 +22120,15 @@ msgstr "" msgid "Enable integration" msgstr "" +msgid "Enable issues tab in global search results" +msgstr "" + msgid "Enable maintenance mode" msgstr "" +msgid "Enable merge requests tab in global search results" +msgstr "" + msgid "Enable multipart emails" msgstr "" @@ -22138,6 +22156,9 @@ msgstr "" msgid "Enable security training" msgstr "" +msgid "Enable snippet tab in global search results" +msgstr "" + msgid "Enable two-factor authentication" msgstr "" @@ -22153,9 +22174,15 @@ msgstr "" msgid "Enable user deactivation emails" msgstr "" +msgid "Enable users tab in global search results" +msgstr "" + msgid "Enable version check" msgstr "" +msgid "Enable wiki tab in global search results" +msgstr "" + msgid "EnableReviewApp|Add a job in your CI/CD configuration that:" msgstr "" @@ -26361,6 +26388,9 @@ msgstr "" msgid "Global SAML group membership lock" msgstr "" +msgid "Global Search" +msgstr "" + msgid "Global Search is disabled for this scope" msgstr "" diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 47c9626711e5d4735185d4b5f800feddff974d2c..80f63b4049c09d8cba76ac7e8b49e5f90a8bf1cf 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -270,15 +270,15 @@ context 'for tab feature flags' do subject(:show) { get :show, params: { scope: scope, search: 'term' }, format: :html } - where(:feature_flag, :scope) do - :global_search_issues_tab | 'issues' - :global_search_merge_requests_tab | 'merge_requests' - :global_search_users_tab | 'users' + where(:admin_setting, :scope) do + :global_search_issues_enabled | 'issues' + :global_search_merge_requests_enabled | 'merge_requests' + :global_search_users_enabled | 'users' end with_them do it 'returns 200 if flag is enabled' do - stub_feature_flags(feature_flag => true) + stub_application_setting(admin_setting => true) show @@ -286,7 +286,7 @@ end it 'redirects with alert if flag is disabled' do - stub_feature_flags(feature_flag => false) + stub_application_setting(admin_setting => false) show diff --git a/spec/helpers/application_settings_helper_spec.rb b/spec/helpers/application_settings_helper_spec.rb index 6c915b288d333d1cef9c783935d34cc38ceae2fb..6f1dc1704e33a6fc0d406d1c1fa5d6ff5db8b5d2 100644 --- a/spec/helpers/application_settings_helper_spec.rb +++ b/spec/helpers/application_settings_helper_spec.rb @@ -83,6 +83,16 @@ ]) end + it 'contains search parameters' do + expected_fields = %i[ + global_search_snippet_titles_enabled + global_search_users_enabled + global_search_issues_enabled + global_search_merge_requests_enabled + ] + expect(helper.visible_attributes).to include(*expected_fields) + end + it 'contains GitLab for Slack app parameters' do params = %i[slack_app_enabled slack_app_id slack_app_secret slack_app_signing_secret slack_app_verification_token] @@ -355,6 +365,28 @@ end end + describe '#global_search_settings_checkboxes', feature_category: :global_search do + let_it_be(:application_setting) { build(:application_setting) } + + before do + application_setting.global_search_issues_enabled = true + application_setting.global_search_merge_requests_enabled = false + application_setting.global_search_users_enabled = false + application_setting.global_search_snippet_titles_enabled = true + helper.instance_variable_set(:@application_setting, application_setting) + end + + it 'returns correctly checked checkboxes' do + helper.gitlab_ui_form_for(application_setting, url: search_admin_application_settings_path) do |form| + result = helper.global_search_settings_checkboxes(form) + expect(result[0]).to have_checked_field('Enable issues tab in global search results', with: 1) + expect(result[1]).not_to have_checked_field('Enable merge requests tab in global search results', with: 1) + expect(result[2]).to have_checked_field('Enable snippet tab in global search results', with: 1) + expect(result[3]).not_to have_checked_field('Enable users tab in global search results', with: 1) + end + end + end + describe '#restricted_level_checkboxes' do let_it_be(:application_setting) { create(:application_setting) } diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 615ff95c7c7768db45317d405df5a2cd8fc1e40c..bd18d29372037edc5474c3c703ad67f1753d9113 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -473,9 +473,9 @@ def simple_sanitize(str) end end - context 'when global_search_users_tab feature flag is disabled' do + context 'when global_search_users_enabled setting is disabled' do before do - stub_feature_flags(global_search_users_tab: false) + stub_application_setting(global_search_users_enabled: false) end it 'does not return results' do @@ -524,9 +524,9 @@ def simple_sanitize(str) end end - context 'when global_search_users_tab feature flag is disabled' do + context 'when global_search_users_enabled setting is disabled' do before do - stub_feature_flags(global_search_users_tab: false) + stub_application_setting(global_search_users_enabled: false) end it 'does not return results' do diff --git a/spec/lib/search/navigation_spec.rb b/spec/lib/search/navigation_spec.rb index 7f8ff6322f9ec5d7c3058419ea93bebba146ebcb..23a9996ae05fac3ba75865229d3ebcfcf358f12f 100644 --- a/spec/lib/search/navigation_spec.rb +++ b/spec/lib/search/navigation_spec.rb @@ -94,7 +94,7 @@ end context 'for issues tab' do - where(:tab_enabled, :feature_flag_enabled, :project, :condition) do + where(:tab_enabled, :setting_enabled, :project, :condition) do false | false | nil | false false | true | nil | true false | true | ref(:project_double) | false @@ -107,8 +107,8 @@ with_them do before do - stub_feature_flags(global_search_issues_tab: feature_flag_enabled) allow(search_navigation).to receive(:tab_enabled_for_project?).with(:issues).and_return(tab_enabled) + stub_application_setting(global_search_issues_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -118,7 +118,7 @@ end context 'for merge requests tab' do - where(:tab_enabled, :feature_flag_enabled, :project, :condition) do + where(:tab_enabled, :setting_enabled, :project, :condition) do false | false | nil | false true | false | nil | true false | false | ref(:project_double) | false @@ -131,8 +131,8 @@ with_them do before do - stub_feature_flags(global_search_merge_requests_tab: feature_flag_enabled) allow(search_navigation).to receive(:tab_enabled_for_project?).with(:merge_requests).and_return(tab_enabled) + stub_application_setting(global_search_merge_requests_enabled: setting_enabled) end it 'data item condition is set correctly' do @@ -219,7 +219,7 @@ end context 'for users tab' do - where(:feature_flag_enabled, :can_read_users_list, :project, :tab_enabled, :condition) do + where(:setting_enabled, :can_read_users_list, :project, :tab_enabled, :condition) do false | false | ref(:project_double) | true | true false | false | nil | false | false false | true | nil | false | false @@ -230,7 +230,7 @@ with_them do before do - stub_feature_flags(global_search_users_tab: feature_flag_enabled) + stub_application_setting(global_search_users_enabled: setting_enabled) allow(search_navigation).to receive(:tab_enabled_for_project?).with(:users).and_return(tab_enabled) allow(search_navigation).to receive(:can?) .with(user, :read_users_list, project_double).and_return(can_read_users_list) @@ -243,7 +243,7 @@ end context 'for snippet_titles tab' do - where(:project, :show_snippets, :feature_flag_enabled, :condition) do + where(:project, :show_snippets, :setting_enabled, :condition) do ref(:project_double) | true | false | false nil | false | false | false ref(:project_double) | false | false | false @@ -258,7 +258,7 @@ let(:options) { { show_snippets: show_snippets } } before do - stub_feature_flags(global_search_snippet_titles_tab: feature_flag_enabled) + stub_application_setting(global_search_snippet_titles_enabled: setting_enabled) end it 'data item condition is set correctly' do diff --git a/spec/migrations/20250109055316_migrate_global_search_settings_in_application_settings_spec.rb b/spec/migrations/20250109055316_migrate_global_search_settings_in_application_settings_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..1c8e51f9dfa3c96bab261ec105a5e0246fd38516 --- /dev/null +++ b/spec/migrations/20250109055316_migrate_global_search_settings_in_application_settings_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe MigrateGlobalSearchSettingsInApplicationSettings, feature_category: :global_search do + let!(:application_setting) { table(:application_settings).create! } + + describe '#down' do + let(:migration) { described_class.new } + + context 'when search settings is already set' do + it 'does not update the search settings' do + migration.up + expect { migration.down }.to change { application_setting.reload.search }.to({}) + end + end + end + + describe '#up' do + context 'when search is not already set' do + before do + stub_feature_flags(global_search_code_tab: false) + stub_feature_flags(global_search_commits_tab: false) + stub_feature_flags(global_search_issues_tab: false) + end + + it 'migrates search from the feature flags in the application_settings successfully' do + expected_search = if ::Gitlab.ee? + { + 'global_search_code_enabled' => false, + 'global_search_commits_enabled' => false, + 'global_search_epics_enabled' => true, + 'global_search_issues_enabled' => false, + 'global_search_merge_requests_enabled' => true, + 'global_search_snippet_titles_enabled' => true, + 'global_search_users_enabled' => true, + 'global_search_wiki_enabled' => true + } + else + { + 'global_search_issues_enabled' => false, + 'global_search_merge_requests_enabled' => true, + 'global_search_snippet_titles_enabled' => true, + 'global_search_users_enabled' => true + } + end + + expect { migrate! }.to change { + application_setting.reload.search + }.from({}).to(expected_search) + end + end + end +end diff --git a/spec/requests/api/search_spec.rb b/spec/requests/api/search_spec.rb index 3b61cef054673ee83576e5e832039e86c5a603f6..3e8e1eb9f34057e78de52eb6c952e50e4576cea2 100644 --- a/spec/requests/api/search_spec.rb +++ b/spec/requests/api/search_spec.rb @@ -419,7 +419,7 @@ context 'global snippet search is disabled' do it 'returns forbidden response' do - stub_feature_flags(global_search_snippet_titles_tab: false) + stub_application_setting(global_search_snippet_titles_enabled: false) get api(endpoint, user), params: { search: 'awesome', scope: 'snippet_titles' } expect(response).to have_gitlab_http_status(:forbidden) end @@ -427,7 +427,7 @@ context 'global snippet search is enabled' do it 'returns ok response' do - stub_feature_flags(global_search_snippet_titles_tab: true) + stub_application_setting(global_search_snippet_titles_enabled: true) get api(endpoint, user), params: { search: 'awesome', scope: 'snippet_titles' } expect(response).to have_gitlab_http_status(:ok) end diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb index d8f36e01b0fb2802a735528bb7913b63d56fe579..ffb8e9cf974df530adcf4481f614d395cba5101d 100644 --- a/spec/routing/admin_routing_spec.rb +++ b/spec/routing/admin_routing_spec.rb @@ -213,3 +213,10 @@ expect(get("/admin/runners/runner_setup_scripts")).to route_to('admin/runners#runner_setup_scripts') end end + +RSpec.describe Admin::ApplicationSettingsController, 'routing', feature_category: :global_search do + it 'redirects /search to #search' do + expect(get('/admin/application_settings/search')).to route_to('admin/application_settings#search') + expect(patch('/admin/application_settings/search')).to route_to('admin/application_settings#search') + end +end diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index e54218e82f032101989046613aa5224defdc4d89..e7dde0ecf6dd48ce2c3addbca200babaf448d692 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -489,21 +489,21 @@ using RSpec::Parameterized::TableSyntax let(:search) { 'foobar' } - where(:scope, :feature_flag, :enabled, :expected) do - 'issues' | :global_search_issues_tab | false | false - 'issues' | :global_search_issues_tab | true | true - 'merge_requests' | :global_search_merge_requests_tab | false | false - 'merge_requests' | :global_search_merge_requests_tab | true | true - 'snippet_titles' | :global_search_snippet_titles_tab | false | false - 'snippet_titles' | :global_search_snippet_titles_tab | true | true - 'users' | :global_search_users_tab | false | false - 'users' | :global_search_users_tab | true | true - 'random' | :random | nil | true + where(:scope, :admin_setting, :setting_enabled, :expected) do + 'issues' | :global_search_issues_enabled | false | false + 'issues' | :global_search_issues_enabled | true | true + 'merge_requests' | :global_search_merge_requests_enabled | false | false + 'merge_requests' | :global_search_merge_requests_enabled | true | true + 'snippet_titles' | :global_search_snippet_titles_enabled | false | false + 'snippet_titles' | :global_search_snippet_titles_enabled | true | true + 'users' | :global_search_users_enabled | false | false + 'users' | :global_search_users_enabled | true | true + 'random' | :random | nil | true end with_them do it 'returns false when feature_flag is not enabled and returns true when feature_flag is enabled' do - stub_feature_flags(feature_flag => enabled) + stub_application_setting(admin_setting => setting_enabled) expect(search_service.global_search_enabled_for_scope?).to eq expected end end @@ -516,13 +516,13 @@ end it 'returns false when feature_flag is not enabled' do - stub_feature_flags(global_search_snippet_titles_tab: false) + stub_application_setting(global_search_snippet_titles_enabled: false) expect(search_service.global_search_enabled_for_scope?).to eq false end it 'returns true when feature_flag is enabled' do - stub_feature_flags(global_search_snippet_titles_tab: true) + stub_application_setting(global_search_snippet_titles_enabled: true) expect(search_service.global_search_enabled_for_scope?).to eq true end