From af5fe4ac92733c481c420b2360631a3ba3500e48 Mon Sep 17 00:00:00 2001
From: Aleksei Lipniagov <alipniagov@gitlab.com>
Date: Tue, 5 Dec 2023 12:40:33 +0000
Subject: [PATCH] Introduce AI-powered settings UI behind FF

Introduce updated UI preparing for CS GA.
It is hidden behind FF as it will only debut in 16.8.
---
 .../application_setting_implementation.rb     |  1 +
 .../application_settings/general.html.haml    |  5 +-
 ...pdated_ai_powered_features_menu_for_sm.yml |  8 +++
 .../admin/application_settings_helper.rb      | 26 +++++++++
 .../helpers/ee/application_settings_helper.rb |  1 +
 .../_ai_powered.html.haml                     | 33 +++++++++++
 .../admin/application_settings_helper_spec.rb | 14 +++++
 .../general.html.haml_spec.rb                 | 57 +++++++++++++++++++
 locale/gitlab.pot                             | 18 ++++++
 .../general.html.haml_spec.rb                 |  3 +-
 10 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 config/feature_flags/development/updated_ai_powered_features_menu_for_sm.yml
 create mode 100644 ee/app/views/admin/application_settings/_ai_powered.html.haml

diff --git a/app/models/application_setting_implementation.rb b/app/models/application_setting_implementation.rb
index 16991937e2f3..bb1368f6dc1e 100644
--- a/app/models/application_setting_implementation.rb
+++ b/app/models/application_setting_implementation.rb
@@ -110,6 +110,7 @@ def defaults # rubocop:disable Metrics/AbcSize
         housekeeping_gc_period: 200,
         housekeeping_incremental_repack_period: 10,
         import_sources: Settings.gitlab['import_sources'],
+        instance_level_ai_beta_features_enabled: false,
         instance_level_code_suggestions_enabled: false,
         invisible_captcha_enabled: false,
         issues_create_limit: 300,
diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml
index d84fbe94f651..0ba883872a17 100644
--- a/app/views/admin/application_settings/general.html.haml
+++ b/app/views/admin/application_settings/general.html.haml
@@ -120,4 +120,7 @@
 = render_if_exists 'admin/application_settings/add_license'
 = render 'admin/application_settings/jira_connect'
 = render 'admin/application_settings/slack'
-= render_if_exists 'admin/application_settings/ai_access'
+- if Feature.enabled?(:updated_ai_powered_features_menu_for_sm)
+  = render_if_exists 'admin/application_settings/ai_powered'
+- else
+  = render_if_exists 'admin/application_settings/ai_access'
diff --git a/config/feature_flags/development/updated_ai_powered_features_menu_for_sm.yml b/config/feature_flags/development/updated_ai_powered_features_menu_for_sm.yml
new file mode 100644
index 000000000000..64377eacd5d0
--- /dev/null
+++ b/config/feature_flags/development/updated_ai_powered_features_menu_for_sm.yml
@@ -0,0 +1,8 @@
+---
+name: updated_ai_powered_features_menu_for_sm
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/138337
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/433255
+milestone: '16.7'
+type: development
+group: group::cloud connector
+default_enabled: false
diff --git a/ee/app/helpers/admin/application_settings_helper.rb b/ee/app/helpers/admin/application_settings_helper.rb
index 0d9b5101306d..a924d3a302b7 100644
--- a/ee/app/helpers/admin/application_settings_helper.rb
+++ b/ee/app/helpers/admin/application_settings_helper.rb
@@ -22,6 +22,20 @@ def code_suggestions_agreement
       s_('CodeSuggestionsSM|By enabling this feature, you agree to the %{terms_link_start}GitLab Testing Agreement%{link_end} and acknowledge that GitLab will send data from the instance, including personal data, to our %{ai_docs_link_start}AI providers%{link_end} to provide this feature.')
         .html_safe % { terms_link_start: terms_link_start, ai_docs_link_start: ai_docs_link_start, link_end: '</a>'.html_safe }
     end
+
+    def ai_powered_testing_agreement
+      terms_link_start = ai_powered_link_start(gitlab_testing_agreement_url)
+
+      s_('AIPoweredSM|By enabling this feature, you agree to the %{terms_link_start}GitLab Testing Agreement%{link_end}.')
+        .html_safe % { terms_link_start: terms_link_start, link_end: '</a>'.html_safe }
+    end
+
+    def ai_powered_description
+      link_start = ai_powered_link_start(ai_powered_docs_url)
+
+      s_('AIPoweredSM|Enable %{link_start}AI-powered features%{link_end} for this instance.')
+        .html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+    end
     # rubocop:enable Layout/LineLength
     # rubocop:enable Style/FormatString
     # rubocop:enable Rails/OutputSafety
@@ -42,12 +56,24 @@ def code_suggestions_agreement_url
     def code_suggestions_ai_docs_url
       'https://docs.gitlab.com/ee/user/ai_features.html#third-party-services'
     end
+
+    def ai_powered_docs_url
+      'https://docs.gitlab.com/ee/user/ai_features.html'
+    end
+
+    def gitlab_testing_agreement_url
+      'https://about.gitlab.com/handbook/legal/testing-agreement/'
+    end
     # rubocop:enable Gitlab/DocUrl
 
     # rubocop:disable Rails/OutputSafety
     def code_suggestions_link_start(url)
       "<a href=\"#{url}\" target=\"_blank\" rel=\"noopener noreferrer\">".html_safe
     end
+
+    def ai_powered_link_start(url)
+      "<a href=\"#{url}\" target=\"_blank\" rel=\"noopener noreferrer\">".html_safe
+    end
     # rubocop:enable Rails/OutputSafety
   end
 end
diff --git a/ee/app/helpers/ee/application_settings_helper.rb b/ee/app/helpers/ee/application_settings_helper.rb
index ef9f97f5d889..b104cfe509e1 100644
--- a/ee/app/helpers/ee/application_settings_helper.rb
+++ b/ee/app/helpers/ee/application_settings_helper.rb
@@ -44,6 +44,7 @@ def visible_attributes
         :geo_node_allowed_ips,
         :geo_status_timeout,
         :help_text,
+        :instance_level_ai_beta_features_enabled,
         :instance_level_code_suggestions_enabled,
         :lock_memberships_to_ldap,
         :lock_memberships_to_saml,
diff --git a/ee/app/views/admin/application_settings/_ai_powered.html.haml b/ee/app/views/admin/application_settings/_ai_powered.html.haml
new file mode 100644
index 000000000000..801a77dd4996
--- /dev/null
+++ b/ee/app/views/admin/application_settings/_ai_powered.html.haml
@@ -0,0 +1,33 @@
+- return if Gitlab.org_or_com?
+- return unless License.feature_available?(:code_suggestions) || License.feature_available?(:ai_chat)
+
+- expanded = false
+
+%section.settings.no-animate#js-ai-powered-settings{ class: ('expanded' if expanded) }
+  .settings-header
+    %h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
+      = s_('AIPoweredSM|AI-powered features')
+    = render Pajamas::ButtonComponent.new(button_options: { class: 'js-settings-toggle' }) do
+      = expanded ? _('Collapse') : _('Expand')
+    %p.gl-text-secondary
+      = ai_powered_description
+
+  .settings-content
+    = gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-ai-powered-settings'), html: { class: 'fieldset-form', id: 'ai-powered-settings' } do |f|
+      = form_errors(@application_setting)
+
+      %fieldset
+        .form-group
+          %h5.settings-header-controls
+            =  s_('CodeSuggestionsSM|Code Suggestions %{beta}').html_safe % { beta: gl_badge_tag(_('Beta'), variant: :neutral, size: :sm) }
+          = f.gitlab_ui_checkbox_component :instance_level_code_suggestions_enabled,
+            s_('CodeSuggestionsSM|Enable Code Suggestions for this instance'),
+            help_text: ai_powered_testing_agreement
+
+          %h5.settings-header-controls
+            = s_('AIPoweredSM|AI-powered features')
+          = f.gitlab_ui_checkbox_component :instance_level_ai_beta_features_enabled,
+            s_('AIPoweredSM|Enable Experiment and Beta AI-powered features'),
+            help_text: ai_powered_testing_agreement
+
+      = f.submit _('Save changes'), pajamas_button: true
diff --git a/ee/spec/helpers/admin/application_settings_helper_spec.rb b/ee/spec/helpers/admin/application_settings_helper_spec.rb
index 0b2698b727e9..f8f41c88524b 100644
--- a/ee/spec/helpers/admin/application_settings_helper_spec.rb
+++ b/ee/spec/helpers/admin/application_settings_helper_spec.rb
@@ -16,4 +16,18 @@
       it { is_expected.to include 'https://about.gitlab.com/handbook/legal/testing-agreement/' }
     end
   end
+
+  describe 'AI-Powered features settings for Self-Managed instances' do
+    describe '#ai_powered_description' do
+      subject { helper.ai_powered_description }
+
+      it { is_expected.to include 'https://docs.gitlab.com/ee/user/ai_features.html' }
+    end
+
+    describe '#ai_powered_testing_agreement' do
+      subject { helper.ai_powered_testing_agreement }
+
+      it { is_expected.to include 'https://about.gitlab.com/handbook/legal/testing-agreement/' }
+    end
+  end
 end
diff --git a/ee/spec/views/admin/application_settings/general.html.haml_spec.rb b/ee/spec/views/admin/application_settings/general.html.haml_spec.rb
index b71042a5561f..1bc0463e3638 100644
--- a/ee/spec/views/admin/application_settings/general.html.haml_spec.rb
+++ b/ee/spec/views/admin/application_settings/general.html.haml_spec.rb
@@ -183,4 +183,61 @@
       end
     end
   end
+
+  describe 'instance-level ai-powered beta features settings', feature_category: :duo_chat do
+    before do
+      allow(::Gitlab).to receive(:org_or_com?).and_return(gitlab_org_or_com?)
+      stub_licensed_features(ai_chat: false)
+    end
+
+    shared_examples 'does not render the form' do
+      it 'does not render the form' do
+        render
+        expect(rendered).not_to have_field('application_setting_instance_level_ai_beta_features_enabled')
+      end
+    end
+
+    context 'when on .com or .org' do
+      let(:gitlab_org_or_com?) { true }
+
+      it_behaves_like 'does not render the form'
+    end
+
+    context 'when not on .com and not on .org' do
+      let(:gitlab_org_or_com?) { false }
+
+      context 'with license', :with_license do
+        context 'with :ai_chat feature available' do
+          before do
+            stub_licensed_features(ai_chat: true)
+          end
+
+          it 'renders the form' do
+            render
+            expect(rendered).to have_field('application_setting_instance_level_ai_beta_features_enabled')
+          end
+
+          context 'with :updated_ai_powered_features_menu_for_sm FF disabled' do
+            before do
+              stub_feature_flags(updated_ai_powered_features_menu_for_sm: false)
+            end
+
+            it_behaves_like 'does not render the form'
+          end
+        end
+
+        context 'with :ai_chat feature not available' do
+          before do
+            stub_licensed_features(ai_chat: false)
+          end
+
+          it_behaves_like 'does not render the form'
+        end
+      end
+
+      context 'with no license', :without_license do
+        it_behaves_like 'does not render the form'
+      end
+    end
+  end
 end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index dd05b368fa1d..6bbd06dd5dc5 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1915,6 +1915,18 @@ msgstr ""
 msgid "AI-generated summary"
 msgstr ""
 
+msgid "AIPoweredSM|AI-powered features"
+msgstr ""
+
+msgid "AIPoweredSM|By enabling this feature, you agree to the %{terms_link_start}GitLab Testing Agreement%{link_end}."
+msgstr ""
+
+msgid "AIPoweredSM|Enable %{link_start}AI-powered features%{link_end} for this instance."
+msgstr ""
+
+msgid "AIPoweredSM|Enable Experiment and Beta AI-powered features"
+msgstr ""
+
 msgid "AISummary|Generates a summary of all comments"
 msgstr ""
 
@@ -11931,6 +11943,12 @@ msgstr ""
 msgid "CodeSuggestionsSM|Code Suggestions"
 msgstr ""
 
+msgid "CodeSuggestionsSM|Code Suggestions %{beta}"
+msgstr ""
+
+msgid "CodeSuggestionsSM|Enable Code Suggestions for this instance"
+msgstr ""
+
 msgid "CodeSuggestionsSM|Enable Code Suggestions for this instance %{beta}"
 msgstr ""
 
diff --git a/spec/views/admin/application_settings/general.html.haml_spec.rb b/spec/views/admin/application_settings/general.html.haml_spec.rb
index 99564003d59f..ad581ee60935 100644
--- a/spec/views/admin/application_settings/general.html.haml_spec.rb
+++ b/spec/views/admin/application_settings/general.html.haml_spec.rb
@@ -115,7 +115,7 @@
   end
 
   # for the licensed tests, refer to ee/spec/views/admin/application_settings/general.html.haml_spec.rb
-  describe 'instance-level code suggestions settings', :without_license, feature_category: :code_suggestions do
+  describe 'instance-level ai-powered settings', :without_license, feature_category: :code_suggestions do
     before do
       allow(::Gitlab).to receive(:org_or_com?).and_return(gitlab_org_or_com?)
 
@@ -125,6 +125,7 @@
     shared_examples 'does not render the form' do
       it 'does not render the form' do
         expect(rendered).not_to have_field('application_setting_instance_level_code_suggestions_enabled')
+        expect(rendered).not_to have_field('application_setting_instance_level_ai_beta_features_enabled')
       end
     end
 
-- 
GitLab