Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sidebars/projects')
-rw-r--r--lib/sidebars/projects/context.rb11
-rw-r--r--lib/sidebars/projects/menus/analytics_menu.rb95
-rw-r--r--lib/sidebars/projects/menus/ci_cd_menu.rb118
-rw-r--r--lib/sidebars/projects/menus/confluence_menu.rb43
-rw-r--r--lib/sidebars/projects/menus/deployments_menu.rb87
-rw-r--r--lib/sidebars/projects/menus/external_issue_tracker_menu.rb59
-rw-r--r--lib/sidebars/projects/menus/external_wiki_menu.rb52
-rw-r--r--lib/sidebars/projects/menus/hidden_menu.rb105
-rw-r--r--lib/sidebars/projects/menus/infrastructure_menu.rb99
-rw-r--r--lib/sidebars/projects/menus/issues_menu.rb135
-rw-r--r--lib/sidebars/projects/menus/labels_menu.rb50
-rw-r--r--lib/sidebars/projects/menus/learn_gitlab_menu.rb62
-rw-r--r--lib/sidebars/projects/menus/members_menu.rb43
-rw-r--r--lib/sidebars/projects/menus/merge_requests_menu.rb70
-rw-r--r--lib/sidebars/projects/menus/monitor_menu.rb246
-rw-r--r--lib/sidebars/projects/menus/packages_registries_menu.rb75
-rw-r--r--lib/sidebars/projects/menus/project_information_menu.rb136
-rw-r--r--lib/sidebars/projects/menus/repository_menu.rb123
-rw-r--r--lib/sidebars/projects/menus/scope_menu.rb19
-rw-r--r--lib/sidebars/projects/menus/security_compliance_menu.rb64
-rw-r--r--lib/sidebars/projects/menus/settings_menu.rb154
-rw-r--r--lib/sidebars/projects/menus/snippets_menu.rb41
-rw-r--r--lib/sidebars/projects/menus/wiki_menu.rb41
-rw-r--r--lib/sidebars/projects/panel.rb51
24 files changed, 1979 insertions, 0 deletions
diff --git a/lib/sidebars/projects/context.rb b/lib/sidebars/projects/context.rb
new file mode 100644
index 00000000000..4c82309035d
--- /dev/null
+++ b/lib/sidebars/projects/context.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ class Context < ::Sidebars::Context
+ def initialize(current_user:, container:, **args)
+ super(current_user: current_user, container: container, project: container, **args)
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/analytics_menu.rb b/lib/sidebars/projects/menus/analytics_menu.rb
new file mode 100644
index 00000000000..660965005c3
--- /dev/null
+++ b/lib/sidebars/projects/menus/analytics_menu.rb
@@ -0,0 +1,95 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class AnalyticsMenu < ::Sidebars::Menu
+ include Gitlab::Utils::StrongMemoize
+
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless can?(context.current_user, :read_analytics, context.project)
+
+ add_item(ci_cd_analytics_menu_item)
+ add_item(repository_analytics_menu_item)
+ add_item(cycle_analytics_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ return cycle_analytics_menu_item.link if cycle_analytics_menu_item.render?
+
+ renderable_items.first.link
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-analytics'
+ }
+ end
+
+ override :title
+ def title
+ _('Analytics')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'chart'
+ end
+
+ private
+
+ def ci_cd_analytics_menu_item
+ if !context.project.feature_available?(:builds, context.current_user) ||
+ !can?(context.current_user, :read_build, context.project) ||
+ context.project.empty_repo?
+ return ::Sidebars::NilMenuItem.new(item_id: :ci_cd_analytics)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('CI/CD'),
+ link: charts_project_pipelines_path(context.project),
+ active_routes: { path: 'pipelines#charts' },
+ item_id: :ci_cd_analytics
+ )
+ end
+
+ def repository_analytics_menu_item
+ if context.project.empty_repo?
+ return ::Sidebars::NilMenuItem.new(item_id: :repository_analytics)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Repository'),
+ link: charts_project_graph_path(context.project, context.current_ref),
+ container_html_options: { class: 'shortcuts-repository-charts' },
+ active_routes: { path: 'graphs#charts' },
+ item_id: :repository_analytics
+ )
+ end
+
+ def cycle_analytics_menu_item
+ strong_memoize(:cycle_analytics_menu_item) do
+ unless can?(context.current_user, :read_cycle_analytics, context.project)
+ next ::Sidebars::NilMenuItem.new(item_id: :cycle_analytics)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Value Stream'),
+ link: project_cycle_analytics_path(context.project),
+ container_html_options: { class: 'shortcuts-project-cycle-analytics' },
+ active_routes: { path: 'cycle_analytics#show' },
+ item_id: :cycle_analytics
+ )
+ end
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::AnalyticsMenu.prepend_mod_with('Sidebars::Projects::Menus::AnalyticsMenu')
diff --git a/lib/sidebars/projects/menus/ci_cd_menu.rb b/lib/sidebars/projects/menus/ci_cd_menu.rb
new file mode 100644
index 00000000000..042ad17fdfc
--- /dev/null
+++ b/lib/sidebars/projects/menus/ci_cd_menu.rb
@@ -0,0 +1,118 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class CiCdMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return unless can?(context.current_user, :read_build, context.project)
+
+ add_item(pipelines_menu_item)
+ add_item(pipelines_editor_menu_item)
+ add_item(jobs_menu_item)
+ add_item(artifacts_menu_item)
+ add_item(pipeline_schedules_menu_item)
+ end
+
+ override :link
+ def link
+ project_pipelines_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-pipelines rspec-link-pipelines'
+ }
+ end
+
+ override :title
+ def title
+ _('CI/CD')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-pipelines-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'rocket'
+ end
+
+ private
+
+ def pipelines_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Pipelines'),
+ link: project_pipelines_path(context.project),
+ container_html_options: { class: 'shortcuts-pipelines' },
+ active_routes: { path: pipelines_routes },
+ item_id: :pipelines
+ )
+ end
+
+ def pipelines_routes
+ %w[
+ pipelines#index
+ pipelines#show
+ pipelines#new
+ ]
+ end
+
+ def pipelines_editor_menu_item
+ unless context.can_view_pipeline_editor
+ return ::Sidebars::NilMenuItem.new(item_id: :pipelines_editor)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: s_('Pipelines|Editor'),
+ link: project_ci_pipeline_editor_path(context.project),
+ active_routes: { path: 'projects/ci/pipeline_editor#show' },
+ item_id: :pipelines_editor
+ )
+ end
+
+ def jobs_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Jobs'),
+ link: project_jobs_path(context.project),
+ container_html_options: { class: 'shortcuts-builds' },
+ active_routes: { controller: :jobs },
+ item_id: :jobs
+ )
+ end
+
+ def artifacts_menu_item
+ unless Feature.enabled?(:artifacts_management_page, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :artifacts)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Artifacts'),
+ link: project_artifacts_path(context.project),
+ container_html_options: { class: 'shortcuts-builds' },
+ active_routes: { path: 'artifacts#index' },
+ item_id: :artifacts
+ )
+ end
+
+ def pipeline_schedules_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Schedules'),
+ link: pipeline_schedules_path(context.project),
+ container_html_options: { class: 'shortcuts-builds' },
+ active_routes: { controller: :pipeline_schedules },
+ item_id: :pipeline_schedules
+ )
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::CiCdMenu.prepend_mod_with('Sidebars::Projects::Menus::CiCdMenu')
diff --git a/lib/sidebars/projects/menus/confluence_menu.rb b/lib/sidebars/projects/menus/confluence_menu.rb
new file mode 100644
index 00000000000..0d83238fa82
--- /dev/null
+++ b/lib/sidebars/projects/menus/confluence_menu.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class ConfluenceMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_wikis_confluence_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-confluence'
+ }
+ end
+
+ override :title
+ def title
+ _('Confluence')
+ end
+
+ override :image_path
+ def image_path
+ 'confluence.svg'
+ end
+
+ override :image_html_options
+ def image_html_options
+ {
+ alt: title
+ }
+ end
+
+ override :render?
+ def render?
+ context.project.has_confluence?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/deployments_menu.rb b/lib/sidebars/projects/menus/deployments_menu.rb
new file mode 100644
index 00000000000..f3d13e12258
--- /dev/null
+++ b/lib/sidebars/projects/menus/deployments_menu.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class DeploymentsMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false if Feature.disabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml)
+
+ add_item(feature_flags_menu_item)
+ add_item(environments_menu_item)
+ add_item(releases_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ renderable_items.first.link
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-deployments'
+ }
+ end
+
+ override :title
+ def title
+ _('Deployments')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'environment'
+ end
+
+ private
+
+ def feature_flags_menu_item
+ unless can?(context.current_user, :read_feature_flag, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :feature_flags)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Feature Flags'),
+ link: project_feature_flags_path(context.project),
+ active_routes: { controller: :feature_flags },
+ container_html_options: { class: 'shortcuts-feature-flags' },
+ item_id: :feature_flags
+ )
+ end
+
+ def environments_menu_item
+ unless can?(context.current_user, :read_environment, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :environments)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Environments'),
+ link: project_environments_path(context.project),
+ active_routes: { controller: :environments },
+ container_html_options: { class: 'shortcuts-environments' },
+ item_id: :environments
+ )
+ end
+
+ def releases_menu_item
+ if !can?(context.current_user, :read_release, context.project) ||
+ context.project.empty_repo?
+ return ::Sidebars::NilMenuItem.new(item_id: :releases)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Releases'),
+ link: project_releases_path(context.project),
+ item_id: :releases,
+ active_routes: { controller: :releases },
+ container_html_options: { class: 'shortcuts-deployments-releases' }
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/external_issue_tracker_menu.rb b/lib/sidebars/projects/menus/external_issue_tracker_menu.rb
new file mode 100644
index 00000000000..136d30f38c3
--- /dev/null
+++ b/lib/sidebars/projects/menus/external_issue_tracker_menu.rb
@@ -0,0 +1,59 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class ExternalIssueTrackerMenu < ::Sidebars::Menu
+ override :link
+ def link
+ external_issue_tracker.issue_tracker_path
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ class: 'shortcuts-external_tracker'
+ }
+ end
+
+ override :extra_collapsed_container_html_options
+ def extra_collapsed_container_html_options
+ {
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ }
+ end
+
+ override :title
+ def title
+ external_issue_tracker.title
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-issues-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'external-link'
+ end
+
+ override :render?
+ def render?
+ external_issue_tracker.present?
+ end
+
+ private
+
+ def external_issue_tracker
+ @external_issue_tracker ||= context.project.external_issue_tracker
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/external_wiki_menu.rb b/lib/sidebars/projects/menus/external_wiki_menu.rb
new file mode 100644
index 00000000000..825f0ca5e8b
--- /dev/null
+++ b/lib/sidebars/projects/menus/external_wiki_menu.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class ExternalWikiMenu < ::Sidebars::Menu
+ override :link
+ def link
+ external_wiki.external_wiki_url
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ target: '_blank',
+ rel: 'noopener noreferrer',
+ class: 'shortcuts-external_wiki'
+ }
+ end
+
+ override :extra_collapsed_container_html_options
+ def extra_collapsed_container_html_options
+ {
+ target: '_blank',
+ rel: 'noopener noreferrer'
+ }
+ end
+
+ override :title
+ def title
+ s_('ExternalWikiService|External wiki')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'external-link'
+ end
+
+ override :render?
+ def render?
+ external_wiki.present?
+ end
+
+ private
+
+ def external_wiki
+ @external_wiki ||= context.project.external_wiki
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/hidden_menu.rb b/lib/sidebars/projects/menus/hidden_menu.rb
new file mode 100644
index 00000000000..c273ee8b74f
--- /dev/null
+++ b/lib/sidebars/projects/menus/hidden_menu.rb
@@ -0,0 +1,105 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class HiddenMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ add_item(activity_menu_item)
+ add_item(graph_menu_item)
+ add_item(new_issue_menu_item)
+ add_item(jobs_menu_item)
+ add_item(commits_menu_item)
+ add_item(issue_boards_menu_item)
+
+ true
+ end
+
+ private
+
+ def activity_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Activity'),
+ link: activity_project_path(context.project),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-project-activity' },
+ item_id: :activity
+ )
+ end
+
+ def graph_menu_item
+ if !can?(context.current_user, :download_code, context.project) ||
+ context.project.empty_repo?
+ return ::Sidebars::NilMenuItem.new(item_id: :graph)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Graph'),
+ link: project_network_path(context.project, context.current_ref),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-network' },
+ item_id: :graph
+ )
+ end
+
+ def new_issue_menu_item
+ unless can?(context.current_user, :read_issue, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :new_issue)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Create a new issue'),
+ link: new_project_issue_path(context.project),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-new-issue' },
+ item_id: :new_issue
+ )
+ end
+
+ def jobs_menu_item
+ unless can?(context.current_user, :read_build, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :jobs)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Jobs'),
+ link: project_jobs_path(context.project),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-builds' },
+ item_id: :jobs
+ )
+ end
+
+ def commits_menu_item
+ if !can?(context.current_user, :download_code, context.project) ||
+ context.project.empty_repo?
+ return ::Sidebars::NilMenuItem.new(item_id: :commits)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Commits'),
+ link: project_commits_path(context.project),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-commits' },
+ item_id: :commits
+ )
+ end
+
+ def issue_boards_menu_item
+ unless can?(context.current_user, :read_issue, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :issue_boards)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Issue Boards'),
+ link: project_boards_path(context.project),
+ active_routes: {},
+ container_html_options: { class: 'shortcuts-issue-boards' },
+ item_id: :issue_boards
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/infrastructure_menu.rb b/lib/sidebars/projects/menus/infrastructure_menu.rb
new file mode 100644
index 00000000000..75b6cae295f
--- /dev/null
+++ b/lib/sidebars/projects/menus/infrastructure_menu.rb
@@ -0,0 +1,99 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class InfrastructureMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false if Feature.disabled?(:sidebar_refactor, context.current_user)
+ return false unless context.project.feature_available?(:operations, context.current_user)
+
+ add_item(kubernetes_menu_item)
+ add_item(serverless_menu_item)
+ add_item(terraform_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ project_clusters_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-infrastructure'
+ }
+ end
+
+ override :title
+ def title
+ _('Infrastructure')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'cloud-gear'
+ end
+
+ private
+
+ def kubernetes_menu_item
+ unless can?(context.current_user, :read_cluster, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :kubernetes)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Kubernetes clusters'),
+ link: project_clusters_path(context.project),
+ active_routes: { controller: [:cluster_agents, :clusters] },
+ container_html_options: { class: 'shortcuts-kubernetes' },
+ hint_html_options: kubernetes_hint_html_options,
+ item_id: :kubernetes
+ )
+ end
+
+ def kubernetes_hint_html_options
+ return {} unless context.show_cluster_hint
+
+ { disabled: true,
+ data: { trigger: 'manual',
+ container: 'body',
+ placement: 'right',
+ highlight: UserCalloutsHelper::GKE_CLUSTER_INTEGRATION,
+ highlight_priority: UserCallout.feature_names[:GKE_CLUSTER_INTEGRATION],
+ dismiss_endpoint: user_callouts_path,
+ auto_devops_help_path: help_page_path('topics/autodevops/index.md') } }
+ end
+
+ def serverless_menu_item
+ unless can?(context.current_user, :read_cluster, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :serverless)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Serverless platform'),
+ link: project_serverless_functions_path(context.project),
+ active_routes: { controller: :functions },
+ item_id: :serverless
+ )
+ end
+
+ def terraform_menu_item
+ unless can?(context.current_user, :read_terraform_state, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :terraform)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Terraform'),
+ link: project_terraform_index_path(context.project),
+ active_routes: { controller: :terraform },
+ item_id: :terraform
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/issues_menu.rb b/lib/sidebars/projects/menus/issues_menu.rb
new file mode 100644
index 00000000000..9840f644179
--- /dev/null
+++ b/lib/sidebars/projects/menus/issues_menu.rb
@@ -0,0 +1,135 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class IssuesMenu < ::Sidebars::Menu
+ include Gitlab::Utils::StrongMemoize
+
+ override :configure_menu_items
+ def configure_menu_items
+ return unless can?(context.current_user, :read_issue, context.project)
+
+ add_item(list_menu_item)
+ add_item(boards_menu_item)
+ add_item(labels_menu_item)
+ add_item(service_desk_menu_item)
+ add_item(milestones_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ project_issues_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-issues'
+ }
+ end
+
+ override :title
+ def title
+ _('Issues')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-issues-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'issues'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: 'projects/issues' }
+ end
+
+ override :has_pill?
+ def has_pill?
+ strong_memoize(:has_pill) do
+ context.project.issues_enabled?
+ end
+ end
+
+ override :pill_count
+ def pill_count
+ strong_memoize(:pill_count) do
+ context.project.open_issues_count(context.current_user)
+ end
+ end
+
+ override :pill_html_options
+ def pill_html_options
+ {
+ class: 'issue_counter'
+ }
+ end
+
+ private
+
+ def list_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('List'),
+ link: project_issues_path(context.project),
+ active_routes: { path: 'projects/issues#index' },
+ container_html_options: { aria: { label: _('Issues') } },
+ item_id: :issue_list
+ )
+ end
+
+ def boards_menu_item
+ title = context.project.multiple_issue_boards_available? ? s_('IssueBoards|Boards') : s_('IssueBoards|Board')
+
+ ::Sidebars::MenuItem.new(
+ title: title,
+ link: project_boards_path(context.project),
+ active_routes: { controller: :boards },
+ item_id: :boards
+ )
+ end
+
+ def labels_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user)
+ return ::Sidebars::NilMenuItem.new(item_id: :labels)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Labels'),
+ link: project_labels_path(context.project),
+ active_routes: { controller: :labels },
+ item_id: :labels
+ )
+ end
+
+ def service_desk_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Service Desk'),
+ link: service_desk_project_issues_path(context.project),
+ active_routes: { path: 'issues#service_desk' },
+ item_id: :service_desk
+ )
+ end
+
+ def milestones_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Milestones'),
+ link: project_milestones_path(context.project),
+ active_routes: { controller: :milestones },
+ item_id: :milestones
+ )
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::IssuesMenu.prepend_mod_with('Sidebars::Projects::Menus::IssuesMenu')
diff --git a/lib/sidebars/projects/menus/labels_menu.rb b/lib/sidebars/projects/menus/labels_menu.rb
new file mode 100644
index 00000000000..12cf0444994
--- /dev/null
+++ b/lib/sidebars/projects/menus/labels_menu.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class LabelsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_labels_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-labels'
+ }
+ end
+
+ override :title
+ def title
+ _('Labels')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-labels-link'
+ }
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :labels }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'label'
+ end
+
+ override :render?
+ def render?
+ return false if Feature.enabled?(:sidebar_refactor, context.current_user)
+
+ can?(context.current_user, :read_label, context.project) && !context.project.issues_enabled?
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/learn_gitlab_menu.rb b/lib/sidebars/projects/menus/learn_gitlab_menu.rb
new file mode 100644
index 00000000000..e3fcd8f25d5
--- /dev/null
+++ b/lib/sidebars/projects/menus/learn_gitlab_menu.rb
@@ -0,0 +1,62 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class LearnGitlabMenu < ::Sidebars::Menu
+ include Gitlab::Utils::StrongMemoize
+
+ override :link
+ def link
+ project_learn_gitlab_path(context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :learn_gitlab }
+ end
+
+ override :title
+ def title
+ _('Learn GitLab')
+ end
+
+ override :has_pill?
+ def has_pill?
+ context.learn_gitlab_experiment_enabled
+ end
+
+ override :pill_count
+ def pill_count
+ strong_memoize(:pill_count) do
+ percentage = LearnGitlab::Onboarding.new(context.project.namespace).completed_percentage
+
+ "#{percentage}%"
+ end
+ end
+
+ override :extra_container_html_options
+ def nav_link_html_options
+ {
+ class: 'home',
+ data: {
+ track_action: 'click_menu',
+ track_property: context.learn_gitlab_experiment_tracking_category,
+ track_label: 'learn_gitlab'
+ }
+ }
+ end
+
+ override :image_path
+ def image_path
+ 'learn_gitlab/graduation_hat.svg'
+ end
+
+ override :render?
+ def render?
+ context.learn_gitlab_experiment_enabled
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/members_menu.rb b/lib/sidebars/projects/menus/members_menu.rb
new file mode 100644
index 00000000000..498bfa74261
--- /dev/null
+++ b/lib/sidebars/projects/menus/members_menu.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class MembersMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_project_members_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ id: 'js-onboarding-members-link'
+ }
+ end
+
+ override :title
+ def title
+ _('Members')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'users'
+ end
+
+ override :render?
+ def render?
+ return false if Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml)
+
+ can?(context.current_user, :read_project_member, context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :project_members }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/merge_requests_menu.rb b/lib/sidebars/projects/menus/merge_requests_menu.rb
new file mode 100644
index 00000000000..fe501667d37
--- /dev/null
+++ b/lib/sidebars/projects/menus/merge_requests_menu.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class MergeRequestsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_merge_requests_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-merge_requests'
+ }
+ end
+
+ override :title
+ def title
+ _('Merge requests')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-mr-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'git-merge'
+ end
+
+ override :render?
+ def render?
+ can?(context.current_user, :read_merge_request, context.project) &&
+ context.project.repo_exists?
+ end
+
+ override :has_pill?
+ def has_pill?
+ true
+ end
+
+ override :pill_count
+ def pill_count
+ @pill_count ||= context.project.open_merge_requests_count
+ end
+
+ override :pill_html_options
+ def pill_html_options
+ {
+ class: 'merge_counter js-merge-counter'
+ }
+ end
+
+ override :active_routes
+ def active_routes
+ if context.project.issues_enabled?
+ { controller: :merge_requests }
+ else
+ { controller: [:merge_requests, :milestones] }
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/monitor_menu.rb b/lib/sidebars/projects/menus/monitor_menu.rb
new file mode 100644
index 00000000000..18c990d0e1f
--- /dev/null
+++ b/lib/sidebars/projects/menus/monitor_menu.rb
@@ -0,0 +1,246 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class MonitorMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless context.project.feature_available?(:operations, context.current_user)
+
+ add_item(metrics_dashboard_menu_item)
+ add_item(logs_menu_item)
+ add_item(tracing_menu_item)
+ add_item(error_tracking_menu_item)
+ add_item(alert_management_menu_item)
+ add_item(incidents_menu_item)
+ add_item(serverless_menu_item)
+ add_item(terraform_menu_item)
+ add_item(kubernetes_menu_item)
+ add_item(environments_menu_item)
+ add_item(feature_flags_menu_item)
+ add_item(product_analytics_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ if can?(context.current_user, :read_environment, context.project)
+ metrics_project_environments_path(context.project)
+ else
+ project_feature_flags_path(context.project)
+ end
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ? 'shortcuts-monitor' : 'shortcuts-operations'
+ }
+ end
+
+ override :title
+ def title
+ Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ? _('Monitor') : _('Operations')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ? 'monitor' : 'cloud-gear'
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: [:user, :gcp] }
+ end
+
+ private
+
+ def metrics_dashboard_menu_item
+ unless can?(context.current_user, :metrics_dashboard, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :metrics)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Metrics'),
+ link: project_metrics_dashboard_path(context.project),
+ active_routes: { path: 'metrics_dashboard#show' },
+ container_html_options: { class: 'shortcuts-metrics' },
+ item_id: :metrics
+ )
+ end
+
+ def logs_menu_item
+ if !can?(context.current_user, :read_environment, context.project) ||
+ !can?(context.current_user, :read_pod_logs, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :logs)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Logs'),
+ link: project_logs_path(context.project),
+ active_routes: { path: 'logs#index' },
+ item_id: :logs
+ )
+ end
+
+ def tracing_menu_item
+ if !can?(context.current_user, :read_environment, context.project) ||
+ !can?(context.current_user, :admin_project, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :tracing)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Tracing'),
+ link: project_tracing_path(context.project),
+ active_routes: { path: 'tracings#show' },
+ item_id: :tracing
+ )
+ end
+
+ def error_tracking_menu_item
+ unless can?(context.current_user, :read_sentry_issue, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :error_tracking)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Error Tracking'),
+ link: project_error_tracking_index_path(context.project),
+ active_routes: { controller: :error_tracking },
+ item_id: :error_tracking
+ )
+ end
+
+ def alert_management_menu_item
+ unless can?(context.current_user, :read_alert_management_alert, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :alert_management)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Alerts'),
+ link: project_alert_management_index_path(context.project),
+ active_routes: { controller: :alert_management },
+ item_id: :alert_management
+ )
+ end
+
+ def incidents_menu_item
+ unless can?(context.current_user, :read_issue, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :incidents)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Incidents'),
+ link: project_incidents_path(context.project),
+ active_routes: { controller: [:incidents, :incident_management] },
+ item_id: :incidents
+ )
+ end
+
+ def serverless_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user) ||
+ !can?(context.current_user, :read_cluster, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :serverless)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Serverless'),
+ link: project_serverless_functions_path(context.project),
+ active_routes: { controller: :functions },
+ item_id: :serverless
+ )
+ end
+
+ def terraform_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user) ||
+ !can?(context.current_user, :read_terraform_state, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :terraform)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Terraform'),
+ link: project_terraform_index_path(context.project),
+ active_routes: { controller: :terraform },
+ item_id: :terraform
+ )
+ end
+
+ def kubernetes_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user) ||
+ !can?(context.current_user, :read_cluster, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :kubernetes)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Kubernetes'),
+ link: project_clusters_path(context.project),
+ active_routes: { controller: [:cluster_agents, :clusters] },
+ container_html_options: { class: 'shortcuts-kubernetes' },
+ hint_html_options: kubernetes_hint_html_options,
+ item_id: :kubernetes
+ )
+ end
+
+ def kubernetes_hint_html_options
+ return {} unless context.show_cluster_hint
+
+ { disabled: true,
+ data: { trigger: 'manual',
+ container: 'body',
+ placement: 'right',
+ highlight: UserCalloutsHelper::GKE_CLUSTER_INTEGRATION,
+ highlight_priority: UserCallout.feature_names[:GKE_CLUSTER_INTEGRATION],
+ dismiss_endpoint: user_callouts_path,
+ auto_devops_help_path: help_page_path('topics/autodevops/index.md') } }
+ end
+
+ def environments_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ||
+ !can?(context.current_user, :read_environment, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :environments)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Environments'),
+ link: project_environments_path(context.project),
+ active_routes: { controller: :environments },
+ container_html_options: { class: 'shortcuts-environments' },
+ item_id: :environments
+ )
+ end
+
+ def feature_flags_menu_item
+ if Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ||
+ !can?(context.current_user, :read_feature_flag, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :feature_flags)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Feature Flags'),
+ link: project_feature_flags_path(context.project),
+ active_routes: { controller: :feature_flags },
+ container_html_options: { class: 'shortcuts-feature-flags' },
+ item_id: :feature_flags
+ )
+ end
+
+ def product_analytics_menu_item
+ if Feature.disabled?(:product_analytics, context.project) ||
+ !can?(context.current_user, :read_product_analytics, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :product_analytics)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Product Analytics'),
+ link: project_product_analytics_path(context.project),
+ active_routes: { controller: :product_analytics },
+ item_id: :product_analytics
+ )
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::MonitorMenu.prepend_mod_with('Sidebars::Projects::Menus::MonitorMenu')
diff --git a/lib/sidebars/projects/menus/packages_registries_menu.rb b/lib/sidebars/projects/menus/packages_registries_menu.rb
new file mode 100644
index 00000000000..7087916bb04
--- /dev/null
+++ b/lib/sidebars/projects/menus/packages_registries_menu.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class PackagesRegistriesMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ add_item(packages_registry_menu_item)
+ add_item(container_registry_menu_item)
+ add_item(infrastructure_registry_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ renderable_items.first.link
+ end
+
+ override :title
+ def title
+ _('Packages & Registries')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'package'
+ end
+
+ private
+
+ def packages_registry_menu_item
+ if !::Gitlab.config.packages.enabled || !can?(context.current_user, :read_package, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :packages_registry)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Package Registry'),
+ link: project_packages_path(context.project),
+ active_routes: { controller: :packages },
+ item_id: :packages_registry,
+ container_html_options: { class: 'shortcuts-container-registry' }
+ )
+ end
+
+ def container_registry_menu_item
+ if !::Gitlab.config.registry.enabled || !can?(context.current_user, :read_container_image, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :container_registry)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Container Registry'),
+ link: project_container_registry_index_path(context.project),
+ active_routes: { controller: :repositories },
+ item_id: :container_registry
+ )
+ end
+
+ def infrastructure_registry_menu_item
+ if Feature.disabled?(:infrastructure_registry_page, context.current_user)
+ return ::Sidebars::NilMenuItem.new(item_id: :infrastructure_registry)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Infrastructure Registry'),
+ link: project_infrastructure_registry_index_path(context.project),
+ active_routes: { controller: :infrastructure_registry },
+ item_id: :infrastructure_registry
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/project_information_menu.rb b/lib/sidebars/projects/menus/project_information_menu.rb
new file mode 100644
index 00000000000..cbb34714087
--- /dev/null
+++ b/lib/sidebars/projects/menus/project_information_menu.rb
@@ -0,0 +1,136 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class ProjectInformationMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ add_item(details_menu_item)
+ add_item(activity_menu_item)
+ add_item(releases_menu_item)
+ add_item(labels_menu_item)
+ add_item(members_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ project_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-project rspec-project-link'
+ }
+ end
+
+ override :nav_link_html_options
+ def nav_link_html_options
+ { class: 'home' }
+ end
+
+ override :title
+ def title
+ if Feature.enabled?(:sidebar_refactor, context.current_user)
+ _('Project information')
+ else
+ _('Project overview')
+ end
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ if Feature.enabled?(:sidebar_refactor, context.current_user)
+ 'project'
+ else
+ 'home'
+ end
+ end
+
+ override :active_routes
+ def active_routes
+ return {} if Feature.disabled?(:sidebar_refactor, context.current_user)
+
+ { path: 'projects#show' }
+ end
+
+ private
+
+ def details_menu_item
+ return if Feature.enabled?(:sidebar_refactor, context.current_user)
+
+ ::Sidebars::MenuItem.new(
+ title: _('Details'),
+ link: project_path(context.project),
+ active_routes: { path: 'projects#show' },
+ item_id: :project_overview,
+ container_html_options: {
+ aria: { label: _('Project details') },
+ class: 'shortcuts-project'
+ }
+ )
+ end
+
+ def activity_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Activity'),
+ link: activity_project_path(context.project),
+ active_routes: { path: 'projects#activity' },
+ item_id: :activity,
+ container_html_options: { class: 'shortcuts-project-activity' }
+ )
+ end
+
+ def releases_menu_item
+ return ::Sidebars::NilMenuItem.new(item_id: :releases) unless show_releases?
+
+ ::Sidebars::MenuItem.new(
+ title: _('Releases'),
+ link: project_releases_path(context.project),
+ item_id: :releases,
+ active_routes: { controller: :releases },
+ container_html_options: { class: 'shortcuts-project-releases' }
+ )
+ end
+
+ def show_releases?
+ Feature.disabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) &&
+ can?(context.current_user, :read_release, context.project) &&
+ !context.project.empty_repo?
+ end
+
+ def labels_menu_item
+ if Feature.disabled?(:sidebar_refactor, context.current_user)
+ return ::Sidebars::NilMenuItem.new(item_id: :labels)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Labels'),
+ link: project_labels_path(context.project),
+ active_routes: { controller: :labels },
+ item_id: :labels
+ )
+ end
+
+ def members_menu_item
+ if Feature.disabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml)
+ return ::Sidebars::NilMenuItem.new(item_id: :members)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Members'),
+ link: project_project_members_path(context.project),
+ active_routes: { controller: :project_members },
+ item_id: :members,
+ container_html_options: {
+ id: 'js-onboarding-members-link'
+ }
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/repository_menu.rb b/lib/sidebars/projects/menus/repository_menu.rb
new file mode 100644
index 00000000000..a784aecc3dc
--- /dev/null
+++ b/lib/sidebars/projects/menus/repository_menu.rb
@@ -0,0 +1,123 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class RepositoryMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless can?(context.current_user, :download_code, context.project)
+ return false if context.project.empty_repo?
+
+ add_item(files_menu_item)
+ add_item(commits_menu_item)
+ add_item(branches_menu_item)
+ add_item(tags_menu_item)
+ add_item(contributors_menu_item)
+ add_item(graphs_menu_item)
+ add_item(compare_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ project_tree_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-tree'
+ }
+ end
+
+ override :title
+ def title
+ _('Repository')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-repo-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'doc-text'
+ end
+
+ private
+
+ def files_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Files'),
+ link: project_tree_path(context.project, context.current_ref),
+ active_routes: { controller: %w[tree blob blame edit_tree new_tree find_file] },
+ item_id: :files
+ )
+ end
+
+ def commits_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Commits'),
+ link: project_commits_path(context.project, context.current_ref),
+ active_routes: { controller: %w(commit commits) },
+ item_id: :commits,
+ container_html_options: { id: 'js-onboarding-commits-link' }
+ )
+ end
+
+ def branches_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Branches'),
+ link: project_branches_path(context.project),
+ active_routes: { controller: :branches },
+ item_id: :branches,
+ container_html_options: { id: 'js-onboarding-branches-link' }
+ )
+ end
+
+ def tags_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Tags'),
+ link: project_tags_path(context.project),
+ item_id: :tags,
+ active_routes: { controller: :tags }
+ )
+ end
+
+ def contributors_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Contributors'),
+ link: project_graph_path(context.project, context.current_ref),
+ active_routes: { path: 'graphs#show' },
+ item_id: :contributors
+ )
+ end
+
+ def graphs_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Graph'),
+ link: project_network_path(context.project, context.current_ref),
+ active_routes: { controller: :network },
+ item_id: :graphs
+ )
+ end
+
+ def compare_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Compare'),
+ link: project_compare_index_path(context.project, from: context.project.repository.root_ref, to: context.current_ref),
+ active_routes: { controller: :compare },
+ item_id: :compare
+ )
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::RepositoryMenu.prepend_mod_with('Sidebars::Projects::Menus::RepositoryMenu')
diff --git a/lib/sidebars/projects/menus/scope_menu.rb b/lib/sidebars/projects/menus/scope_menu.rb
new file mode 100644
index 00000000000..1d1cf11b271
--- /dev/null
+++ b/lib/sidebars/projects/menus/scope_menu.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class ScopeMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_path(context.project)
+ end
+
+ override :title
+ def title
+ context.project.name
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/security_compliance_menu.rb b/lib/sidebars/projects/menus/security_compliance_menu.rb
new file mode 100644
index 00000000000..6c9fb8312bd
--- /dev/null
+++ b/lib/sidebars/projects/menus/security_compliance_menu.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class SecurityComplianceMenu < ::Sidebars::Menu
+ include Gitlab::Utils::StrongMemoize
+
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless can?(context.current_user, :access_security_and_compliance, context.project)
+
+ add_item(configuration_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ project_security_configuration_path(context.project)
+ end
+
+ override :title
+ def title
+ _('Security & Compliance')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'shield'
+ end
+
+ private
+
+ def configuration_menu_item
+ strong_memoize(:configuration_menu_item) do
+ unless render_configuration_menu_item?
+ next ::Sidebars::NilMenuItem.new(item_id: :configuration)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Configuration'),
+ link: project_security_configuration_path(context.project),
+ active_routes: { path: configuration_menu_item_paths },
+ item_id: :configuration
+ )
+ end
+ end
+
+ def render_configuration_menu_item?
+ can?(context.current_user, :read_security_configuration, context.project)
+ end
+
+ def configuration_menu_item_paths
+ %w[
+ projects/security/configuration#show
+ ]
+ end
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Menus::SecurityComplianceMenu.prepend_mod_with('Sidebars::Projects::Menus::SecurityComplianceMenu')
diff --git a/lib/sidebars/projects/menus/settings_menu.rb b/lib/sidebars/projects/menus/settings_menu.rb
new file mode 100644
index 00000000000..4ea6f5e298a
--- /dev/null
+++ b/lib/sidebars/projects/menus/settings_menu.rb
@@ -0,0 +1,154 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class SettingsMenu < ::Sidebars::Menu
+ override :configure_menu_items
+ def configure_menu_items
+ return false unless can?(context.current_user, :admin_project, context.project)
+
+ add_item(general_menu_item)
+ add_item(integrations_menu_item)
+ add_item(webhooks_menu_item)
+ add_item(access_tokens_menu_item)
+ add_item(repository_menu_item)
+ add_item(ci_cd_menu_item)
+ add_item(monitor_menu_item)
+ add_item(pages_menu_item)
+ add_item(packages_and_registries_menu_item)
+
+ true
+ end
+
+ override :link
+ def link
+ edit_project_path(context.project)
+ end
+
+ override :title
+ def title
+ _('Settings')
+ end
+
+ override :title_html_options
+ def title_html_options
+ {
+ id: 'js-onboarding-settings-link'
+ }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'settings'
+ end
+
+ private
+
+ def general_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('General'),
+ link: edit_project_path(context.project),
+ active_routes: { path: 'projects#edit' },
+ item_id: :general
+ )
+ end
+
+ def integrations_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Integrations'),
+ link: project_settings_integrations_path(context.project),
+ active_routes: { path: %w[integrations#show services#edit] },
+ item_id: :integrations
+ )
+ end
+
+ def webhooks_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Webhooks'),
+ link: project_hooks_path(context.project),
+ active_routes: { path: %w[hooks#index hooks#edit hook_logs#show] },
+ item_id: :webhooks
+ )
+ end
+
+ def access_tokens_menu_item
+ unless can?(context.current_user, :read_resource_access_tokens, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :access_tokens)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Access Tokens'),
+ link: project_settings_access_tokens_path(context.project),
+ active_routes: { path: 'access_tokens#index' },
+ item_id: :access_tokens
+ )
+ end
+
+ def repository_menu_item
+ ::Sidebars::MenuItem.new(
+ title: _('Repository'),
+ link: project_settings_repository_path(context.project),
+ active_routes: { path: 'repository#show' },
+ item_id: :repository
+ )
+ end
+
+ def ci_cd_menu_item
+ if context.project.archived? || !context.project.feature_available?(:builds, context.current_user)
+ return ::Sidebars::NilMenuItem.new(item_id: :ci_cd)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('CI/CD'),
+ link: project_settings_ci_cd_path(context.project),
+ active_routes: { path: 'ci_cd#show' },
+ item_id: :ci_cd
+ )
+ end
+
+ def monitor_menu_item
+ if context.project.archived? || !can?(context.current_user, :admin_operations, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :monitor)
+ end
+
+ title = Feature.enabled?(:sidebar_refactor, context.current_user, default_enabled: :yaml) ? _('Monitor') : _('Operations')
+ ::Sidebars::MenuItem.new(
+ title: title,
+ link: project_settings_operations_path(context.project),
+ active_routes: { path: 'operations#show' },
+ item_id: :monitor
+ )
+ end
+
+ def pages_menu_item
+ unless context.project.pages_available?
+ return ::Sidebars::NilMenuItem.new(item_id: :pages)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Pages'),
+ link: project_pages_path(context.project),
+ active_routes: { path: 'pages#show' },
+ item_id: :pages
+ )
+ end
+
+ def packages_and_registries_menu_item
+ if !Gitlab.config.registry.enabled ||
+ Feature.disabled?(:sidebar_refactor, context.current_user) ||
+ !can?(context.current_user, :destroy_container_image, context.project)
+ return ::Sidebars::NilMenuItem.new(item_id: :packages_and_registries)
+ end
+
+ ::Sidebars::MenuItem.new(
+ title: _('Packages & Registries'),
+ link: project_settings_packages_and_registries_path(context.project),
+ active_routes: { path: 'packages_and_registries#index' },
+ item_id: :packages_and_registries
+ )
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/snippets_menu.rb b/lib/sidebars/projects/menus/snippets_menu.rb
new file mode 100644
index 00000000000..060341b3c51
--- /dev/null
+++ b/lib/sidebars/projects/menus/snippets_menu.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class SnippetsMenu < ::Sidebars::Menu
+ override :link
+ def link
+ project_snippets_path(context.project)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-snippets'
+ }
+ end
+
+ override :title
+ def title
+ _('Snippets')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'snippet'
+ end
+
+ override :render?
+ def render?
+ can?(context.current_user, :read_snippet, context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :snippets }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/menus/wiki_menu.rb b/lib/sidebars/projects/menus/wiki_menu.rb
new file mode 100644
index 00000000000..3980b193fd1
--- /dev/null
+++ b/lib/sidebars/projects/menus/wiki_menu.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ class WikiMenu < ::Sidebars::Menu
+ override :link
+ def link
+ wiki_path(context.project.wiki)
+ end
+
+ override :extra_container_html_options
+ def extra_container_html_options
+ {
+ class: 'shortcuts-wiki'
+ }
+ end
+
+ override :title
+ def title
+ _('Wiki')
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'book'
+ end
+
+ override :render?
+ def render?
+ can?(context.current_user, :read_wiki, context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :wikis }
+ end
+ end
+ end
+ end
+end
diff --git a/lib/sidebars/projects/panel.rb b/lib/sidebars/projects/panel.rb
new file mode 100644
index 00000000000..ac7c043a96e
--- /dev/null
+++ b/lib/sidebars/projects/panel.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ class Panel < ::Sidebars::Panel
+ override :configure_menus
+ def configure_menus
+ set_scope_menu(Sidebars::Projects::Menus::ScopeMenu.new(context))
+ set_hidden_menu(Sidebars::Projects::Menus::HiddenMenu.new(context))
+ add_menus
+ end
+
+ override :aria_label
+ def aria_label
+ _('Project navigation')
+ end
+
+ private
+
+ def add_menus
+ add_menu(Sidebars::Projects::Menus::ProjectInformationMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::LearnGitlabMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::RepositoryMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::IssuesMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::ExternalIssueTrackerMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::LabelsMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::MergeRequestsMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::CiCdMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::SecurityComplianceMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::DeploymentsMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::MonitorMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::InfrastructureMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::PackagesRegistriesMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::AnalyticsMenu.new(context))
+ add_menu(confluence_or_wiki_menu)
+ add_menu(Sidebars::Projects::Menus::ExternalWikiMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::SnippetsMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::MembersMenu.new(context))
+ add_menu(Sidebars::Projects::Menus::SettingsMenu.new(context))
+ end
+
+ def confluence_or_wiki_menu
+ confluence_menu = ::Sidebars::Projects::Menus::ConfluenceMenu.new(context)
+
+ confluence_menu.render? ? confluence_menu : Sidebars::Projects::Menus::WikiMenu.new(context)
+ end
+ end
+ end
+end
+
+Sidebars::Projects::Panel.prepend_mod_with('Sidebars::Projects::Panel')