From 1e9cdbfab3ff15b9c1f526092caecbe322dcbe31 Mon Sep 17 00:00:00 2001
From: Mohamed Moustafa <mmoustafa@gitlab.com>
Date: Mon, 11 Dec 2023 13:43:53 +0000
Subject: [PATCH] Create new route for Code Suggestions page in Admin Area

This creates a Code Suggestions page in the Admin Area for Self-Managed
instances, where the Code Suggestions UI would be added later.

- Add the /admin/code_suggestions route
- Add a "Code Suggestions" entry in the sidebar for SM instances
  to access the page
---
 .../admin/code_suggestions_controller.rb      | 21 +++++
 .../admin/code_suggestions/index.html.haml    |  4 +
 ee/config/routes/admin.rb                     |  2 +
 ee/lib/ee/sidebars/admin/panel.rb             | 14 +++
 .../admin/menus/code_suggestions_menu.rb      | 29 ++++++
 .../admin/menus/code_suggestions_menu_spec.rb | 12 +++
 ee/spec/lib/sidebars/admin/panel_spec.rb      | 45 ++++++++++
 .../admin/code_suggestions_controller_spec.rb | 89 +++++++++++++++++++
 .../admin/subscriptions_controller_spec.rb    |  2 +-
 locale/gitlab.pot                             |  6 ++
 10 files changed, 223 insertions(+), 1 deletion(-)
 create mode 100644 ee/app/controllers/admin/code_suggestions_controller.rb
 create mode 100644 ee/app/views/admin/code_suggestions/index.html.haml
 create mode 100644 ee/lib/sidebars/admin/menus/code_suggestions_menu.rb
 create mode 100644 ee/spec/lib/sidebars/admin/menus/code_suggestions_menu_spec.rb
 create mode 100644 ee/spec/requests/admin/code_suggestions_controller_spec.rb

diff --git a/ee/app/controllers/admin/code_suggestions_controller.rb b/ee/app/controllers/admin/code_suggestions_controller.rb
new file mode 100644
index 0000000000000..e1b2db387ff03
--- /dev/null
+++ b/ee/app/controllers/admin/code_suggestions_controller.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+# EE:Self Managed
+module Admin
+  class CodeSuggestionsController < Admin::ApplicationController
+    include ::GitlabSubscriptions::CodeSuggestionsHelper
+
+    respond_to :html
+
+    feature_category :seat_cost_management
+    urgency :low
+
+    before_action :ensure_on_sm_with_feature_enabled!
+
+    private
+
+    def ensure_on_sm_with_feature_enabled!
+      render_404 unless gitlab_sm? && code_suggestions_available?
+    end
+  end
+end
diff --git a/ee/app/views/admin/code_suggestions/index.html.haml b/ee/app/views/admin/code_suggestions/index.html.haml
new file mode 100644
index 0000000000000..008ce90da9557
--- /dev/null
+++ b/ee/app/views/admin/code_suggestions/index.html.haml
@@ -0,0 +1,4 @@
+-# EE:Self Managed
+- page_title _('Code Suggestions')
+
+#js-code-suggestions-page{ data: {} }
diff --git a/ee/config/routes/admin.rb b/ee/config/routes/admin.rb
index c5fdfaddef895..183f4184bc212 100644
--- a/ee/config/routes/admin.rb
+++ b/ee/config/routes/admin.rb
@@ -43,6 +43,8 @@
 
   resource :subscription, only: [:show]
 
+  get 'code_suggestions', to: 'code_suggestions#index'
+
   # using `only: []` to keep duplicate routes from being created
   resource :application_settings, only: [] do
     get :seat_link_payload
diff --git a/ee/lib/ee/sidebars/admin/panel.rb b/ee/lib/ee/sidebars/admin/panel.rb
index 378614caf42a5..f876bda1b4688 100644
--- a/ee/lib/ee/sidebars/admin/panel.rb
+++ b/ee/lib/ee/sidebars/admin/panel.rb
@@ -4,6 +4,7 @@ module EE
   module Sidebars
     module Admin
       module Panel
+        include ::GitlabSubscriptions::CodeSuggestionsHelper
         extend ::Gitlab::Utils::Override
 
         override :configure_menus
@@ -29,6 +30,19 @@ def configure_menus
             ::Sidebars::Admin::Menus::AbuseReportsMenu,
             ::Sidebars::Admin::Menus::SubscriptionMenu.new(context)
           )
+
+          insert_code_suggestions_menu
+        end
+
+        private
+
+        def insert_code_suggestions_menu
+          return unless gitlab_sm? && code_suggestions_available?
+
+          insert_menu_after(
+            ::Sidebars::Admin::Menus::SubscriptionMenu,
+            ::Sidebars::Admin::Menus::CodeSuggestionsMenu.new(context)
+          )
         end
       end
     end
diff --git a/ee/lib/sidebars/admin/menus/code_suggestions_menu.rb b/ee/lib/sidebars/admin/menus/code_suggestions_menu.rb
new file mode 100644
index 0000000000000..da12837438803
--- /dev/null
+++ b/ee/lib/sidebars/admin/menus/code_suggestions_menu.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+module Sidebars
+  module Admin
+    module Menus
+      class CodeSuggestionsMenu < ::Sidebars::Admin::BaseMenu
+        override :link
+        def link
+          admin_code_suggestions_path
+        end
+
+        override :title
+        def title
+          s_('Admin|Code Suggestions')
+        end
+
+        override :sprite_icon
+        def sprite_icon
+          'tanuki-ai'
+        end
+
+        override :active_routes
+        def active_routes
+          { controller: :code_suggestions }
+        end
+      end
+    end
+  end
+end
diff --git a/ee/spec/lib/sidebars/admin/menus/code_suggestions_menu_spec.rb b/ee/spec/lib/sidebars/admin/menus/code_suggestions_menu_spec.rb
new file mode 100644
index 0000000000000..556b7a0af81a1
--- /dev/null
+++ b/ee/spec/lib/sidebars/admin/menus/code_suggestions_menu_spec.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Sidebars::Admin::Menus::CodeSuggestionsMenu, feature_category: :navigation do
+  it_behaves_like 'Admin menu',
+    link: '/admin/code_suggestions',
+    title: s_('Admin|Code Suggestions'),
+    icon: 'tanuki-ai'
+
+  it_behaves_like 'Admin menu without sub menus', active_routes: { controller: :code_suggestions }
+end
diff --git a/ee/spec/lib/sidebars/admin/panel_spec.rb b/ee/spec/lib/sidebars/admin/panel_spec.rb
index 1605c02a08e92..e77ce870b52b5 100644
--- a/ee/spec/lib/sidebars/admin/panel_spec.rb
+++ b/ee/spec/lib/sidebars/admin/panel_spec.rb
@@ -23,4 +23,49 @@
   it_behaves_like 'a panel with uniquely identifiable menu items'
   it_behaves_like 'a panel without placeholders'
   it_behaves_like 'a panel instantiable by the anonymous user'
+
+  shared_examples 'hides code suggestions menu' do
+    it 'does not render code suggestions menu' do
+      expect(menus).not_to include(instance_of(::Sidebars::Admin::Menus::CodeSuggestionsMenu))
+    end
+  end
+
+  describe '#configure_menus' do
+    let(:menus) { subject.instance_variable_get(:@menus) }
+
+    context 'when instance is self-managed' do
+      before do
+        stub_saas_features(gitlab_saas_subscriptions: false)
+      end
+
+      context 'when self_managed_code_suggestions feature flag is enabled' do
+        it 'renders code suggestions menu' do
+          expect(menus).to include(instance_of(::Sidebars::Admin::Menus::CodeSuggestionsMenu))
+        end
+      end
+
+      context 'when self_managed_code_suggestions feature flag is disabled' do
+        before do
+          stub_feature_flags(self_managed_code_suggestions: false)
+        end
+
+        it_behaves_like 'hides code suggestions menu'
+      end
+    end
+
+    context 'when instance is SaaS' do
+      where(:self_managed_code_suggestions) do
+        [true, false]
+      end
+
+      with_them do
+        before do
+          stub_saas_features(gitlab_saas_subscriptions: true)
+          stub_feature_flags(self_managed_code_suggestions: self_managed_code_suggestions)
+        end
+
+        it_behaves_like 'hides code suggestions menu'
+      end
+    end
+  end
 end
diff --git a/ee/spec/requests/admin/code_suggestions_controller_spec.rb b/ee/spec/requests/admin/code_suggestions_controller_spec.rb
new file mode 100644
index 0000000000000..257d46e5454b6
--- /dev/null
+++ b/ee/spec/requests/admin/code_suggestions_controller_spec.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Admin::CodeSuggestionsController, :cloud_licenses, feature_category: :seat_cost_management do
+  include AdminModeHelper
+
+  describe 'GET /code_suggestions' do
+    before do
+      allow(::Gitlab::Saas).to receive(:feature_available?).and_return(false)
+    end
+
+    shared_examples 'renders the activation form' do
+      it 'renders the activation form' do
+        get admin_code_suggestions_path
+
+        expect(response).to render_template(:index)
+        expect(response.body).to include('js-code-suggestions-page')
+      end
+    end
+
+    shared_examples 'hides code suggestions path' do
+      it 'returns 404' do
+        get admin_code_suggestions_path
+
+        expect(response).to have_gitlab_http_status(:not_found)
+        expect(response).to render_template('errors/not_found')
+      end
+    end
+
+    context 'when the user is not admin' do
+      let_it_be(:user) { create(:user) }
+
+      before do
+        sign_in(user)
+      end
+
+      it_behaves_like 'hides code suggestions path'
+    end
+
+    context 'when the user is an admin' do
+      let_it_be(:admin) { create(:admin) }
+
+      before do
+        login_as(admin)
+        enable_admin_mode!(admin)
+      end
+
+      it_behaves_like 'renders the activation form'
+
+      context 'when instance is self-managed' do
+        before do
+          stub_saas_features(gitlab_saas_subscriptions: false)
+        end
+
+        context 'when self_managed_code_suggestions feature flag is enabled' do
+          before do
+            stub_feature_flags(self_managed_code_suggestions: true)
+          end
+
+          it_behaves_like 'renders the activation form'
+        end
+
+        context 'when self_managed_code_suggestions feature flag is disabled' do
+          before do
+            stub_feature_flags(self_managed_code_suggestions: false)
+          end
+
+          it_behaves_like 'hides code suggestions path'
+        end
+      end
+
+      context 'when instance is SaaS' do
+        where(:self_managed_code_suggestions) do
+          [true, false]
+        end
+
+        with_them do
+          before do
+            stub_saas_features(gitlab_saas_subscriptions: true)
+            stub_feature_flags(self_managed_code_suggestions: self_managed_code_suggestions)
+          end
+
+          it_behaves_like 'hides code suggestions path'
+        end
+      end
+    end
+  end
+end
diff --git a/ee/spec/requests/admin/subscriptions_controller_spec.rb b/ee/spec/requests/admin/subscriptions_controller_spec.rb
index 7a1803b7fde4b..c394851b4effb 100644
--- a/ee/spec/requests/admin/subscriptions_controller_spec.rb
+++ b/ee/spec/requests/admin/subscriptions_controller_spec.rb
@@ -2,7 +2,7 @@
 
 require 'spec_helper'
 
-RSpec.describe Admin::SubscriptionsController, :cloud_licenses, feature_category: :purchase do
+RSpec.describe Admin::SubscriptionsController, :cloud_licenses, feature_category: :seat_cost_management do
   include AdminModeHelper
 
   describe 'GET /subscriptions' do
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b2efcb289d3d4..c996cf851b8f8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4304,6 +4304,9 @@ msgstr ""
 msgid "Admin|CI/CD"
 msgstr ""
 
+msgid "Admin|Code Suggestions"
+msgstr ""
+
 msgid "Admin|Credentials"
 msgstr ""
 
@@ -11873,6 +11876,9 @@ msgstr ""
 msgid "Code Review Analytics displays a table of open merge requests considered to be in code review. There are currently no merge requests in review for this project and/or filters."
 msgstr ""
 
+msgid "Code Suggestions"
+msgstr ""
+
 msgid "Code Suggestions add-on status"
 msgstr ""
 
-- 
GitLab