Refactoring Sidebar Project Panel

In this commit we start the refactor of the project sidebar.

Instead of the current approach with all the logic in views and helpers,
we're moving to a model based structure where each menu model contains
its logic, visibility access levels, and all the necessary info.

Nevertheless, the migration is tricky because we cannot just replace
the whole sidebar (that would be a 130 files MR). In order to
make it incremental we still render the old views. Then, when we
add a new menu to the new structure we'll remove that menu
from the menu, until we migrate all menus and we can remove the view
entirely.
parent be1a7cff
......@@ -14,6 +14,10 @@ module SidebarsHelper
end
end
def project_sidebar_context(project, user)
Sidebars::Context.new(**project_sidebar_context_data(project, user))
end
private
def sidebar_project_tracking_attrs
......@@ -27,4 +31,12 @@ module SidebarsHelper
def sidebar_user_profile_tracking_attrs
tracking_attrs('user_side_navigation', 'render', 'user_side_navigation')
end
def project_sidebar_context_data(project, user)
{
current_user: user,
container: project,
project: project
}
end
end
......@@ -51,5 +51,25 @@ module Sidebars
def renderable_menus
@renderable_menus ||= @menus.select(&:render?)
end
def container
context.container
end
# Auxiliar method that helps with the migration from
# regular views to the new logic
def render_raw_scope_menu_partial
# No-op
end
# Auxiliar method that helps with the migration from
# regular views to the new logic.
#
# Any menu inside this partial will be added after
# all the menus added in the `configure_menus`
# method.
def render_raw_menus_partial
# No-op
end
end
end
# frozen_string_literal: true
module Sidebars
module Projects
class Panel < ::Sidebars::Panel
override :render_raw_menus_partial
def render_raw_scope_menu_partial
'layouts/nav/sidebar/project_scope_menu'
end
override :render_raw_menus_partial
def render_raw_menus_partial
'layouts/nav/sidebar/project_menus'
end
override :aria_label
def aria_label
_('Project navigation')
end
end
end
end
%aside.nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(@project), 'aria-label': _('Project navigation') }
.nav-sidebar-inner-scroll
.context-header
= link_to project_path(@project), title: @project.name do
.avatar-container.rect-avatar.s40.project-avatar
= project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile', width: 40, height: 40)
.sidebar-context-title
= @project.name
%ul.sidebar-top-level-items.qa-project-sidebar
= nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do
= link_to project_path(@project), class: 'shortcuts-project rspec-project-link', data: { qa_selector: 'project_link' } do
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
= _('Project overview')
%ul.sidebar-sub-level-items
= nav_link(path: 'projects#show', html_options: { class: "fly-out-top-item" } ) do
= link_to project_path(@project) do
%strong.fly-out-top-item-name
= _('Project overview')
%li.divider.fly-out-top-item
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: _('Project details'), class: 'shortcuts-project' do
%span= _('Details')
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity', data: { qa_selector: 'activity_link' } do
%span= _('Activity')
- if project_nav_tab?(:releases)
= nav_link(controller: :releases) do
= link_to project_releases_path(@project), title: _('Releases'), class: 'shortcuts-project-releases' do
%span= _('Releases')
- if project_nav_tab? :learn_gitlab
= nav_link(controller: :learn_gitlab, html_options: { class: 'home' }) do
= link_to project_learn_gitlab_path(@project) do
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
= _('Learn GitLab')
- if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do
= link_to project_tree_path(@project), class: 'shortcuts-tree', data: { qa_selector: "repository_link" } do
.nav-icon-container
= sprite_icon('doc-text')
%span.nav-item-name#js-onboarding-repo-link
= _('Repository')
%ul.sidebar-sub-level-items
= nav_link(controller: sidebar_repository_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to project_tree_path(@project) do
%strong.fly-out-top-item-name
= _('Repository')
%li.divider.fly-out-top-item
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_tree_path(@project) do
= _('Files')
= nav_link(controller: [:commit, :commits]) do
= link_to project_commits_path(@project, current_ref), id: 'js-onboarding-commits-link' do
= _('Commits')
= nav_link(html_options: {class: branches_tab_class}) do
= link_to project_branches_path(@project), data: { qa_selector: "branches_link" }, id: 'js-onboarding-branches-link' do
= _('Branches')
= nav_link(controller: [:tags]) do
= link_to project_tags_path(@project), data: { qa_selector: "tags_link" } do
= _('Tags')
= nav_link(path: 'graphs#show') do
= link_to project_graph_path(@project, current_ref) do
= _('Contributors')
= nav_link(controller: %w(network)) do
= link_to project_network_path(@project, current_ref) do
= _('Graph')
= nav_link(controller: :compare) do
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: current_ref) do
= _('Compare')
= render_if_exists 'projects/sidebar/repository_locked_files'
- if project_nav_tab? :issues
= nav_link(controller: @project.issues_enabled? ? ['projects/issues', :labels, :milestones, :boards, :iterations] : 'projects/issues') do
= link_to project_issues_path(@project), class: 'shortcuts-issues qa-issues-item' do
.nav-icon-container
= sprite_icon('issues')
%span.nav-item-name#js-onboarding-issues-link
= _('Issues')
- if @project.issues_enabled?
%span.badge.badge-pill.count.issue_counter
= number_with_delimiter(@project.open_issues_count(current_user))
%ul.sidebar-sub-level-items
= nav_link(controller: 'projects/issues', action: :index, html_options: { class: "fly-out-top-item" } ) do
= link_to project_issues_path(@project) do
%strong.fly-out-top-item-name
= _('Issues')
- if @project.issues_enabled?
%span.badge.badge-pill.count.issue_counter.fly-out-badge
= number_with_delimiter(@project.open_issues_count(current_user))
%li.divider.fly-out-top-item
= nav_link(controller: :issues, action: :index) do
= link_to project_issues_path(@project), title: _('Issues') do
%span
= _('List')
= nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: boards_link_text, data: { qa_selector: "issue_boards_link" } do
%span
= boards_link_text
= nav_link(controller: :labels) do
= link_to project_labels_path(@project), title: _('Labels'), class: 'qa-labels-link' do
%span
= _('Labels')
= render 'projects/sidebar/issues_service_desk'
= nav_link(controller: :milestones) do
= link_to project_milestones_path(@project), title: _('Milestones'), class: 'qa-milestones-link' do
%span
= _('Milestones')
= render_if_exists 'layouts/nav/sidebar/project_iterations_link'
- if project_nav_tab?(:external_issue_tracker)
- issue_tracker = @project.external_issue_tracker
- if issue_tracker.is_a?(JiraService) && project_jira_issues_integration?
= render_if_exists 'layouts/nav/sidebar/project_jira_issues_link', issue_tracker: issue_tracker
- else
= nav_link do
= link_to issue_tracker.issue_tracker_path, target: '_blank', rel: 'noopener noreferrer', class: 'shortcuts-external_tracker' do
.nav-icon-container
= sprite_icon('external-link')
%span.nav-item-name
= issue_tracker.title
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: "fly-out-top-item" } ) do
= link_to issue_tracker.issue_tracker_path, target: '_blank', rel: 'noopener noreferrer' do
%strong.fly-out-top-item-name
= issue_tracker.title
- if (project_nav_tab? :labels) && !@project.issues_enabled?
= nav_link(controller: [:labels]) do
= link_to project_labels_path(@project), title: _('Labels'), class: 'shortcuts-labels qa-labels-items' do
.nav-icon-container
= sprite_icon('label')
%span.nav-item-name#js-onboarding-labels-link
= _('Labels')
- if project_nav_tab? :merge_requests
= nav_link(controller: @project.issues_enabled? ? :merge_requests : [:merge_requests, :milestones]) do
= link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests', data: { qa_selector: 'merge_requests_link' } do
.nav-icon-container
= sprite_icon('git-merge')
%span.nav-item-name#js-onboarding-mr-link
= _('Merge requests')
%span.badge.badge-pill.count.merge_counter.js-merge-counter
= number_with_delimiter(@project.open_merge_requests_count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :merge_requests, html_options: { class: "fly-out-top-item" } ) do
= link_to project_merge_requests_path(@project) do
%strong.fly-out-top-item-name
= _('Merge requests')
%span.badge.badge-pill.count.merge_counter.js-merge-counter.fly-out-badge
= number_with_delimiter(@project.open_merge_requests_count)
= render_if_exists "layouts/nav/requirements_link", project: @project
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts, :test_cases, :pipeline_editor], unless: -> { current_path?('projects/pipelines#charts') }) do
= link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines rspec-link-pipelines', data: { qa_selector: 'ci_cd_link' } do
.nav-icon-container
= sprite_icon('rocket')
%span.nav-item-name#js-onboarding-pipelines-link
= _('CI/CD')
%ul.sidebar-sub-level-items
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts, :test_cases, :pipeline_editor], html_options: { class: "fly-out-top-item" }) do
= link_to project_pipelines_path(@project) do
%strong.fly-out-top-item-name
= _('CI/CD')
%li.divider.fly-out-top-item
- if project_nav_tab? :pipelines
= nav_link(path: ['pipelines#index', 'pipelines#show']) do
= link_to project_pipelines_path(@project), title: _('Pipelines'), class: 'shortcuts-pipelines' do
%span
= _('Pipelines')
- if can_view_pipeline_editor?(@project)
= nav_link(controller: :pipeline_editor, action: :show) do
= link_to project_ci_pipeline_editor_path(@project), title: s_('Pipelines|Editor') do
%span
= s_('Pipelines|Editor')
- if project_nav_tab? :builds
= nav_link(controller: :jobs) do
= link_to project_jobs_path(@project), title: _('Jobs'), class: 'shortcuts-builds' do
%span
= _('Jobs')
- if Feature.enabled?(:artifacts_management_page, @project)
= nav_link(controller: :artifacts, action: :index) do
= link_to project_artifacts_path(@project), title: _('Artifacts'), class: 'shortcuts-builds' do
%span
= _('Artifacts')
- if project_nav_tab?(:pipelines)
= nav_link(controller: :pipeline_schedules) do
= link_to pipeline_schedules_path(@project), title: _('Schedules'), class: 'shortcuts-builds' do
%span
= _('Schedules')
= render_if_exists "layouts/nav/test_cases_link", project: @project
- if project_nav_tab? :security_and_compliance
= render_if_exists 'layouts/nav/sidebar/project_security_link' # EE-specific
- if project_nav_tab? :operations
= nav_link(controller: sidebar_operations_paths) do
= link_to sidebar_operations_link_path, class: 'shortcuts-operations', data: { qa_selector: 'operations_link' } do
.nav-icon-container
= sprite_icon('cloud-gear')
%span.nav-item-name
= _('Operations')
%ul.sidebar-sub-level-items
= nav_link(controller: sidebar_operations_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to sidebar_operations_link_path do
%strong.fly-out-top-item-name
= _('Operations')
%li.divider.fly-out-top-item
- if project_nav_tab? :metrics_dashboards
= nav_link(controller: :metrics_dashboard, action: [:show]) do
= link_to project_metrics_dashboard_path(@project), title: _('Metrics'), class: 'shortcuts-metrics', data: { qa_selector: 'operations_metrics_link' } do
%span
= _('Metrics')
- if project_nav_tab?(:environments) && can?(current_user, :read_pod_logs, @project)
= nav_link(controller: :logs, action: [:index]) do
= link_to project_logs_path(@project), title: _('Logs') do
%span
= _('Logs')
- if project_nav_tab? :environments
= render "layouts/nav/sidebar/tracing_link"
- if project_nav_tab?(:error_tracking)
= nav_link(controller: :error_tracking) do
= link_to project_error_tracking_index_path(@project), title: _('Error Tracking') do
%span
= _('Error Tracking')
- if project_nav_tab?(:alert_management)
= nav_link(controller: :alert_management) do
= link_to project_alert_management_index_path(@project), title: _('Alerts') do
%span
= _('Alerts')
- if project_nav_tab?(:incidents)
= nav_link(controller: :incidents) do
= link_to project_incidents_path(@project), title: _('Incidents'), data: { qa_selector: 'operations_incidents_link' } do
%span
= _('Incidents')
= render_if_exists 'projects/sidebar/oncall_schedules'
- if project_nav_tab? :serverless
= nav_link(controller: :functions) do
= link_to project_serverless_functions_path(@project), title: _('Serverless') do
%span
= _('Serverless')
- if project_nav_tab? :terraform
= nav_link(controller: :terraform) do
= link_to project_terraform_index_path(@project), title: _('Terraform') do
%span
= _('Terraform')
- if project_nav_tab? :clusters
- show_cluster_hint = show_gke_cluster_integration_callout?(@project)
= nav_link(controller: [:cluster_agents, :clusters]) do
= link_to project_clusters_path(@project), title: _('Kubernetes'), class: 'shortcuts-kubernetes' do
%span
= _('Kubernetes')
- if show_cluster_hint
.js-feature-highlight{ 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') } }
- if project_nav_tab? :environments
= nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
= link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
%span
= _('Environments')
- if project_nav_tab? :feature_flags
= nav_link(controller: :feature_flags) do
= link_to project_feature_flags_path(@project), title: _('Feature Flags'), class: 'shortcuts-feature-flags' do
%span
= _('Feature Flags')
- if project_nav_tab?(:product_analytics)
= nav_link(controller: :product_analytics) do
= link_to project_product_analytics_path(@project), title: _('Product Analytics') do
%span
= _('Product Analytics')
= render_if_exists 'layouts/nav/sidebar/project_packages_link'
- if project_nav_tab? :analytics
= render 'layouts/nav/sidebar/analytics_links', links: project_analytics_navbar_links(@project, current_user)
- if project_nav_tab?(:confluence)
- confluence_url = project_wikis_confluence_path(@project)
= nav_link do
= link_to confluence_url, class: 'shortcuts-confluence' do
.nav-icon-container
= image_tag 'confluence.svg', alt: _('Confluence')
%span.nav-item-name
= _('Confluence')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: 'fly-out-top-item' } ) do
= link_to confluence_url, target: '_blank', rel: 'noopener noreferrer' do
%strong.fly-out-top-item-name
= _('Confluence')
- if project_nav_tab? :wiki
= render 'layouts/nav/sidebar/wiki_link', wiki_url: wiki_path(@project.wiki)
- if project_nav_tab?(:external_wiki)
- external_wiki_url = @project.external_wiki.external_wiki_url
= nav_link do
= link_to external_wiki_url, class: 'shortcuts-external_wiki' do
.nav-icon-container
= sprite_icon('external-link')
%span.nav-item-name
= s_('ExternalWikiService|External wiki')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: "fly-out-top-item" } ) do
= link_to external_wiki_url do
%strong.fly-out-top-item-name
= s_('ExternalWikiService|External wiki')
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to project_snippets_path(@project), class: 'shortcuts-snippets', data: { qa_selector: 'snippets_link' } do
.nav-icon-container
= sprite_icon('snippet')
%span.nav-item-name
= _('Snippets')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :snippets, html_options: { class: "fly-out-top-item" } ) do
= link_to project_snippets_path(@project) do
%strong.fly-out-top-item-name
= _('Snippets')
= nav_link(controller: :project_members) do
= link_to project_project_members_path(@project), title: _('Members'), class: 'qa-members-link', id: 'js-onboarding-members-link' do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Members')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do
= link_to project_project_members_path(@project) do
%strong.fly-out-top-item-name
= _('Members')
- if project_nav_tab? :settings
= nav_link(path: sidebar_settings_paths) do
= link_to edit_project_path(@project) do
.nav-icon-container
= sprite_icon('settings')
%span.nav-item-name.qa-settings-item#js-onboarding-settings-link
= _('Settings')
%ul.sidebar-sub-level-items
- can_edit = can?(current_user, :admin_project, @project)
- if can_edit
= nav_link(path: sidebar_settings_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to edit_project_path(@project) do
%strong.fly-out-top-item-name
= _('Settings')
%li.divider.fly-out-top-item
= nav_link(path: %w[projects#edit]) do
= link_to edit_project_path(@project), title: _('General'), class: 'qa-general-settings-link' do
%span
= _('General')
- if can_edit
= nav_link(controller: [:integrations, :services]) do
= link_to project_settings_integrations_path(@project), title: _('Integrations'), data: { qa_selector: 'integrations_settings_link' } do
%span
= _('Integrations')
= nav_link(controller: [:hooks, :hook_logs]) do
= link_to project_hooks_path(@project), title: _('Webhooks'), data: { qa_selector: 'webhooks_settings_link' } do
%span
= _('Webhooks')
- if can?(current_user, :read_resource_access_tokens, @project)
= nav_link(controller: [:access_tokens]) do
= link_to project_settings_access_tokens_path(@project), title: _('Access Tokens'), data: { qa_selector: 'access_tokens_settings_link' } do
%span
= _('Access Tokens')
= nav_link(controller: :repository) do
= link_to project_settings_repository_path(@project), title: _('Repository') do
%span
= _('Repository')
- if !@project.archived? && @project.feature_available?(:builds, current_user)
= nav_link(controller: :ci_cd) do
= link_to project_settings_ci_cd_path(@project), title: _('CI/CD') do
%span
= _('CI/CD')
- if settings_operations_available?
= nav_link(controller: [:operations]) do
= link_to project_settings_operations_path(@project), title: _('Operations'), data: { qa_selector: 'operations_settings_link' } do
= _('Operations')
- if @project.pages_available?
= nav_link(controller: :pages) do
= link_to project_pages_path(@project), title: _('Pages') do
%span
= _('Pages')
-# Shortcut to Project > Activity
%li.hidden
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do
%span
= _('Activity')
-# Shortcut to Repository > Graph (formerly, Network)
- if project_nav_tab? :network
%li.hidden
= link_to project_network_path(@project, current_ref), title: _('Network'), class: 'shortcuts-network' do
= _('Graph')
-# Shortcut to Issues > New Issue
- if project_nav_tab?(:issues)
%li.hidden
= link_to new_project_issue_path(@project), class: 'shortcuts-new-issue' do
= _('Create a new issue')
-# Shortcut to Pipelines > Jobs
- if project_nav_tab? :builds
%li.hidden
= link_to project_jobs_path(@project), title: _('Jobs'), class: 'shortcuts-builds' do
= _('Jobs')
-# Shortcut to commits page
- if project_nav_tab? :commits
%li.hidden
= link_to project_commits_path(@project), title: _('Commits'), class: 'shortcuts-commits' do
= _('Commits')
-# Shortcut to issue boards
- if project_nav_tab?(:issues)
%li.hidden
= link_to _('Issue Boards'), project_boards_path(@project), title: _('Issue Boards'), class: 'shortcuts-issue-boards'
= render 'shared/sidebar_toggle_button'
-# We're migration the project sidebar to a logical model based structure. If you need to update
-# any of the existing menus, you can find them in app/views/layouts/nav/sidebar/_project_menus.html.haml.
= render partial: 'shared/nav/sidebar', object: Sidebars::Projects::Panel.new(project_sidebar_context(@project, current_user))
= nav_link(path: sidebar_projects_paths, html_options: { class: 'home' }) do
= link_to project_path(@project), class: 'shortcuts-project rspec-project-link', data: { qa_selector: 'project_link' } do
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
= _('Project overview')
%ul.sidebar-sub-level-items
= nav_link(path: 'projects#show', html_options: { class: "fly-out-top-item" } ) do
= link_to project_path(@project) do
%strong.fly-out-top-item-name
= _('Project overview')
%li.divider.fly-out-top-item
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: _('Project details'), class: 'shortcuts-project' do
%span= _('Details')
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity', data: { qa_selector: 'activity_link' } do
%span= _('Activity')
- if project_nav_tab?(:releases)
= nav_link(controller: :releases) do
= link_to project_releases_path(@project), title: _('Releases'), class: 'shortcuts-project-releases' do
%span= _('Releases')
- if project_nav_tab? :learn_gitlab
= nav_link(controller: :learn_gitlab, html_options: { class: 'home' }) do
= link_to project_learn_gitlab_path(@project) do
.nav-icon-container
= sprite_icon('home')
%span.nav-item-name
= _('Learn GitLab')
- if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do
= link_to project_tree_path(@project), class: 'shortcuts-tree', data: { qa_selector: "repository_link" } do
.nav-icon-container
= sprite_icon('doc-text')
%span.nav-item-name#js-onboarding-repo-link
= _('Repository')
%ul.sidebar-sub-level-items
= nav_link(controller: sidebar_repository_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to project_tree_path(@project) do
%strong.fly-out-top-item-name
= _('Repository')
%li.divider.fly-out-top-item
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_tree_path(@project) do
= _('Files')
= nav_link(controller: [:commit, :commits]) do
= link_to project_commits_path(@project, current_ref), id: 'js-onboarding-commits-link' do
= _('Commits')
= nav_link(html_options: {class: branches_tab_class}) do
= link_to project_branches_path(@project), data: { qa_selector: "branches_link" }, id: 'js-onboarding-branches-link' do
= _('Branches')
= nav_link(controller: [:tags]) do
= link_to project_tags_path(@project), data: { qa_selector: "tags_link" } do
= _('Tags')
= nav_link(path: 'graphs#show') do
= link_to project_graph_path(@project, current_ref) do
= _('Contributors')
= nav_link(controller: %w(network)) do
= link_to project_network_path(@project, current_ref) do
= _('Graph')
= nav_link(controller: :compare) do
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: current_ref) do
= _('Compare')
= render_if_exists 'projects/sidebar/repository_locked_files'
- if project_nav_tab? :issues
= nav_link(controller: @project.issues_enabled? ? ['projects/issues', :labels, :milestones, :boards, :iterations] : 'projects/issues') do
= link_to project_issues_path(@project), class: 'shortcuts-issues qa-issues-item' do
.nav-icon-container
= sprite_icon('issues')
%span.nav-item-name#js-onboarding-issues-link
= _('Issues')
- if @project.issues_enabled?
%span.badge.badge-pill.count.issue_counter
= number_with_delimiter(@project.open_issues_count(current_user))
%ul.sidebar-sub-level-items
= nav_link(controller: 'projects/issues', action: :index, html_options: { class: "fly-out-top-item" } ) do
= link_to project_issues_path(@project) do
%strong.fly-out-top-item-name
= _('Issues')
- if @project.issues_enabled?
%span.badge.badge-pill.count.issue_counter.fly-out-badge
= number_with_delimiter(@project.open_issues_count(current_user))
%li.divider.fly-out-top-item
= nav_link(controller: :issues, action: :index) do
= link_to project_issues_path(@project), title: _('Issues') do
%span
= _('List')
= nav_link(controller: :boards) do
= link_to project_boards_path(@project), title: boards_link_text, data: { qa_selector: "issue_boards_link" } do
%span
= boards_link_text
= nav_link(controller: :labels) do
= link_to project_labels_path(@project), title: _('Labels'), class: 'qa-labels-link' do
%span
= _('Labels')
= render 'projects/sidebar/issues_service_desk'
= nav_link(controller: :milestones) do
= link_to project_milestones_path(@project), title: _('Milestones'), class: 'qa-milestones-link' do
%span
= _('Milestones')
= render_if_exists 'layouts/nav/sidebar/project_iterations_link'
- if project_nav_tab?(:external_issue_tracker)
- issue_tracker = @project.external_issue_tracker
- if issue_tracker.is_a?(JiraService) && project_jira_issues_integration?
= render_if_exists 'layouts/nav/sidebar/project_jira_issues_link', issue_tracker: issue_tracker
- else
= nav_link do
= link_to issue_tracker.issue_tracker_path, target: '_blank', rel: 'noopener noreferrer', class: 'shortcuts-external_tracker' do
.nav-icon-container
= sprite_icon('external-link')
%span.nav-item-name
= issue_tracker.title
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: "fly-out-top-item" } ) do
= link_to issue_tracker.issue_tracker_path, target: '_blank', rel: 'noopener noreferrer' do
%strong.fly-out-top-item-name
= issue_tracker.title
- if (project_nav_tab? :labels) && !@project.issues_enabled?
= nav_link(controller: [:labels]) do
= link_to project_labels_path(@project), title: _('Labels'), class: 'shortcuts-labels qa-labels-items' do
.nav-icon-container
= sprite_icon('label')
%span.nav-item-name#js-onboarding-labels-link
= _('Labels')
- if project_nav_tab? :merge_requests
= nav_link(controller: @project.issues_enabled? ? :merge_requests : [:merge_requests, :milestones]) do
= link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests', data: { qa_selector: 'merge_requests_link' } do
.nav-icon-container
= sprite_icon('git-merge')
%span.nav-item-name#js-onboarding-mr-link
= _('Merge requests')
%span.badge.badge-pill.count.merge_counter.js-merge-counter
= number_with_delimiter(@project.open_merge_requests_count)
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :merge_requests, html_options: { class: "fly-out-top-item" } ) do
= link_to project_merge_requests_path(@project) do
%strong.fly-out-top-item-name
= _('Merge requests')
%span.badge.badge-pill.count.merge_counter.js-merge-counter.fly-out-badge
= number_with_delimiter(@project.open_merge_requests_count)
= render_if_exists "layouts/nav/requirements_link", project: @project
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts, :test_cases, :pipeline_editor], unless: -> { current_path?('projects/pipelines#charts') }) do
= link_to project_pipelines_path(@project), class: 'shortcuts-pipelines qa-link-pipelines rspec-link-pipelines', data: { qa_selector: 'ci_cd_link' } do
.nav-icon-container
= sprite_icon('rocket')
%span.nav-item-name#js-onboarding-pipelines-link
= _('CI/CD')
%ul.sidebar-sub-level-items
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts, :test_cases, :pipeline_editor], html_options: { class: "fly-out-top-item" }) do
= link_to project_pipelines_path(@project) do
%strong.fly-out-top-item-name
= _('CI/CD')
%li.divider.fly-out-top-item
- if project_nav_tab? :pipelines
= nav_link(path: ['pipelines#index', 'pipelines#show']) do
= link_to project_pipelines_path(@project), title: _('Pipelines'), class: 'shortcuts-pipelines' do
%span
= _('Pipelines')
- if can_view_pipeline_editor?(@project)
= nav_link(controller: :pipeline_editor, action: :show) do
= link_to project_ci_pipeline_editor_path(@project), title: s_('Pipelines|Editor') do
%span
= s_('Pipelines|Editor')
- if project_nav_tab? :builds
= nav_link(controller: :jobs) do
= link_to project_jobs_path(@project), title: _('Jobs'), class: 'shortcuts-builds' do
%span
= _('Jobs')
- if Feature.enabled?(:artifacts_management_page, @project)
= nav_link(controller: :artifacts, action: :index) do
= link_to project_artifacts_path(@project), title: _('Artifacts'), class: 'shortcuts-builds' do
%span
= _('Artifacts')
- if project_nav_tab?(:pipelines)
= nav_link(controller: :pipeline_schedules) do
= link_to pipeline_schedules_path(@project), title: _('Schedules'), class: 'shortcuts-builds' do
%span
= _('Schedules')
= render_if_exists "layouts/nav/test_cases_link", project: @project
- if project_nav_tab? :security_and_compliance
= render_if_exists 'layouts/nav/sidebar/project_security_link' # EE-specific
- if project_nav_tab? :operations
= nav_link(controller: sidebar_operations_paths) do
= link_to sidebar_operations_link_path, class: 'shortcuts-operations', data: { qa_selector: 'operations_link' } do
.nav-icon-container
= sprite_icon('cloud-gear')
%span.nav-item-name
= _('Operations')
%ul.sidebar-sub-level-items
= nav_link(controller: sidebar_operations_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to sidebar_operations_link_path do
%strong.fly-out-top-item-name
= _('Operations')
%li.divider.fly-out-top-item
- if project_nav_tab? :metrics_dashboards
= nav_link(controller: :metrics_dashboard, action: [:show]) do
= link_to project_metrics_dashboard_path(@project), title: _('Metrics'), class: 'shortcuts-metrics', data: { qa_selector: 'operations_metrics_link' } do
%span
= _('Metrics')
- if project_nav_tab?(:environments) && can?(current_user, :read_pod_logs, @project)
= nav_link(controller: :logs, action: [:index]) do
= link_to project_logs_path(@project), title: _('Logs') do
%span
= _('Logs')
- if project_nav_tab? :environments
= render "layouts/nav/sidebar/tracing_link"
- if project_nav_tab?(:error_tracking)
= nav_link(controller: :error_tracking) do
= link_to project_error_tracking_index_path(@project), title: _('Error Tracking') do
%span
= _('Error Tracking')
- if project_nav_tab?(:alert_management)
= nav_link(controller: :alert_management) do
= link_to project_alert_management_index_path(@project), title: _('Alerts') do
%span
= _('Alerts')
- if project_nav_tab?(:incidents)
= nav_link(controller: :incidents) do
= link_to project_incidents_path(@project), title: _('Incidents'), data: { qa_selector: 'operations_incidents_link' } do
%span
= _('Incidents')
= render_if_exists 'projects/sidebar/oncall_schedules'
- if project_nav_tab? :serverless
= nav_link(controller: :functions) do
= link_to project_serverless_functions_path(@project), title: _('Serverless') do
%span
= _('Serverless')
- if project_nav_tab? :terraform
= nav_link(controller: :terraform) do
= link_to project_terraform_index_path(@project), title: _('Terraform') do
%span
= _('Terraform')
- if project_nav_tab? :clusters
- show_cluster_hint = show_gke_cluster_integration_callout?(@project)
= nav_link(controller: [:cluster_agents, :clusters]) do
= link_to project_clusters_path(@project), title: _('Kubernetes'), class: 'shortcuts-kubernetes' do
%span
= _('Kubernetes')
- if show_cluster_hint
.js-feature-highlight{ 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') } }
- if project_nav_tab? :environments
= nav_link(controller: :environments, action: [:index, :folder, :show, :new, :edit, :create, :update, :stop, :terminal]) do
= link_to project_environments_path(@project), title: _('Environments'), class: 'shortcuts-environments qa-operations-environments-link' do
%span
= _('Environments')
- if project_nav_tab? :feature_flags
= nav_link(controller: :feature_flags) do
= link_to project_feature_flags_path(@project), title: _('Feature Flags'), class: 'shortcuts-feature-flags' do
%span
= _('Feature Flags')
- if project_nav_tab?(:product_analytics)
= nav_link(controller: :product_analytics) do
= link_to project_product_analytics_path(@project), title: _('Product Analytics') do
%span
= _('Product Analytics')
= render_if_exists 'layouts/nav/sidebar/project_packages_link'
- if project_nav_tab? :analytics
= render 'layouts/nav/sidebar/analytics_links', links: project_analytics_navbar_links(@project, current_user)
- if project_nav_tab?(:confluence)
- confluence_url = project_wikis_confluence_path(@project)
= nav_link do
= link_to confluence_url, class: 'shortcuts-confluence' do
.nav-icon-container
= image_tag 'confluence.svg', alt: _('Confluence')
%span.nav-item-name
= _('Confluence')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: 'fly-out-top-item' } ) do
= link_to confluence_url, target: '_blank', rel: 'noopener noreferrer' do
%strong.fly-out-top-item-name
= _('Confluence')
- if project_nav_tab? :wiki
= render 'layouts/nav/sidebar/wiki_link', wiki_url: wiki_path(@project.wiki)
- if project_nav_tab?(:external_wiki)
- external_wiki_url = @project.external_wiki.external_wiki_url
= nav_link do
= link_to external_wiki_url, class: 'shortcuts-external_wiki' do
.nav-icon-container
= sprite_icon('external-link')
%span.nav-item-name
= s_('ExternalWikiService|External wiki')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(html_options: { class: "fly-out-top-item" } ) do
= link_to external_wiki_url do
%strong.fly-out-top-item-name
= s_('ExternalWikiService|External wiki')
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to project_snippets_path(@project), class: 'shortcuts-snippets', data: { qa_selector: 'snippets_link' } do
.nav-icon-container
= sprite_icon('snippet')
%span.nav-item-name
= _('Snippets')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(controller: :snippets, html_options: { class: "fly-out-top-item" } ) do
= link_to project_snippets_path(@project) do
%strong.fly-out-top-item-name
= _('Snippets')
= nav_link(controller: :project_members) do
= link_to project_project_members_path(@project), title: _('Members'), class: 'qa-members-link', id: 'js-onboarding-members-link' do
.nav-icon-container
= sprite_icon('users')
%span.nav-item-name
= _('Members')
%ul.sidebar-sub-level-items.is-fly-out-only
= nav_link(path: %w[members#show], html_options: { class: "fly-out-top-item" } ) do
= link_to project_project_members_path(@project) do
%strong.fly-out-top-item-name
= _('Members')
- if project_nav_tab? :settings
= nav_link(path: sidebar_settings_paths) do
= link_to edit_project_path(@project) do
.nav-icon-container
= sprite_icon('settings')
%span.nav-item-name.qa-settings-item#js-onboarding-settings-link
= _('Settings')
%ul.sidebar-sub-level-items
- can_edit = can?(current_user, :admin_project, @project)
- if can_edit
= nav_link(path: sidebar_settings_paths, html_options: { class: "fly-out-top-item" } ) do
= link_to edit_project_path(@project) do
%strong.fly-out-top-item-name
= _('Settings')
%li.divider.fly-out-top-item
= nav_link(path: %w[projects#edit]) do
= link_to edit_project_path(@project), title: _('General'), class: 'qa-general-settings-link' do
%span
= _('General')
- if can_edit
= nav_link(controller: [:integrations, :services]) do
= link_to project_settings_integrations_path(@project), title: _('Integrations'), data: { qa_selector: 'integrations_settings_link' } do
%span
= _('Integrations')
= nav_link(controller: [:hooks, :hook_logs]) do
= link_to project_hooks_path(@project), title: _('Webhooks'), data: { qa_selector: 'webhooks_settings_link' } do
%span
= _('Webhooks')
- if can?(current_user, :read_resource_access_tokens, @project)
= nav_link(controller: [:access_tokens]) do
= link_to project_settings_access_tokens_path(@project), title: _('Access Tokens'), data: { qa_selector: 'access_tokens_settings_link' } do
%span
= _('Access Tokens')
= nav_link(controller: :repository) do
= link_to project_settings_repository_path(@project), title: _('Repository') do
%span
= _('Repository')
- if !@project.archived? && @project.feature_available?(:builds, current_user)
= nav_link(controller: :ci_cd) do
= link_to project_settings_ci_cd_path(@project), title: _('CI/CD') do
%span
= _('CI/CD')
- if settings_operations_available?
= nav_link(controller: [:operations]) do
= link_to project_settings_operations_path(@project), title: _('Operations'), data: { qa_selector: 'operations_settings_link' } do
= _('Operations')
- if @project.pages_available?
= nav_link(controller: :pages) do
= link_to project_pages_path(@project), title: _('Pages') do
%span
= _('Pages')
-# Shortcut to Project > Activity
%li.hidden
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do
%span
= _('Activity')
-# Shortcut to Repository > Graph (formerly, Network)
- if project_nav_tab? :network
%li.hidden
= link_to project_network_path(@project, current_ref), title: _('Network'), class: 'shortcuts-network' do
= _('Graph')
-# Shortcut to Issues > New Issue
- if project_nav_tab?(:issues)
%li.hidden
= link_to new_project_issue_path(@project), class: 'shortcuts-new-issue' do
= _('Create a new issue')
-# Shortcut to Pipelines > Jobs
- if project_nav_tab? :builds
%li.hidden
= link_to project_jobs_path(@project), title: _('Jobs'), class: 'shortcuts-builds' do
= _('Jobs')
-# Shortcut to commits page
- if project_nav_tab? :commits
%li.hidden
= link_to project_commits_path(@project), title: _('Commits'), class: 'shortcuts-commits' do
= _('Commits')
-# Shortcut to issue boards
- if project_nav_tab?(:issues)
%li.hidden
= link_to _('Issue Boards'), project_boards_path(@project), title: _('Issue Boards'), class: 'shortcuts-issue-boards'
.context-header
= link_to project_path(@project), title: @project.name do
.avatar-container.rect-avatar.s40.project-avatar
= project_icon(@project, alt: @project.name, class: 'avatar s40 avatar-tile', width: 40, height: 40)
.sidebar-context-title
= @project.name
%aside.nav-sidebar{ class: ('sidebar-collapsed-desktop' if collapsed_sidebar?), **sidebar_tracking_attributes_by_object(sidebar.container), 'aria-label': sidebar.aria_label }
.nav-sidebar-inner-scroll
- if sidebar.render_raw_scope_menu_partial
= render sidebar.render_raw_scope_menu_partial
%ul.sidebar-top-level-items.qa-project-sidebar
- if sidebar.render_raw_menus_partial
= render sidebar.render_raw_menus_partial
= render 'shared/sidebar_toggle_button'
......@@ -13,7 +13,7 @@ module QA
include SubMenus::Settings
include SubMenus::Packages
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :activity_link
element :merge_requests_link
element :snippets_link
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :link_pipelines
end
end
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :issue_boards_link
element :issues_item
element :labels_link
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :operations_link
element :operations_environments_link
element :operations_metrics_link
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :project_link
end
end
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :repository_link
element :branches_link
element :tags_link
......
......@@ -13,7 +13,7 @@ module QA
base.class_eval do
include QA::Page::Project::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_project.html.haml' do
view 'app/views/layouts/nav/sidebar/_project_menus.html.haml' do
element :settings_item
element :general_settings_link
element :integrations_settings_link
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment