Add Deployments menu to project sidebar

In this commit we add a new `Deployment` menu to the project
sidebar. This menu is going to contain the menu items: `Feature
Flags`, `Environments`, and `Releases`.

These menu items are coming from the `Operations` menu and
also the `Project information` one.
parent 7ece9f25
......@@ -115,8 +115,6 @@ RSpec.describe 'Project navbar' do
_('Error Tracking'),
_('Alerts'),
_('Incidents'),
_('Environments'),
_('Feature Flags'),
_('Product Analytics')
]
end
......@@ -126,7 +124,6 @@ RSpec.describe 'Project navbar' do
nav_item: _('Project information'),
nav_sub_items: [
_('Activity'),
_('Releases'),
_('Labels')
]
}
......@@ -137,6 +134,18 @@ RSpec.describe 'Project navbar' do
insert_package_nav(_('Operations'))
insert_infrastructure_registry_nav
insert_after_nav_item(
_('Security & Compliance'),
new_nav_item: {
nav_item: _('Deployments'),
nav_sub_items: [
_('Feature Flags'),
_('Environments'),
_('Releases')
]
}
)
insert_after_nav_item(
_('Operations'),
new_nav_item: {
......
# 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
......@@ -196,7 +196,8 @@ module Sidebars
end
def environments_menu_item
unless can?(context.current_user, :read_environment, context.project)
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
......@@ -210,7 +211,8 @@ module Sidebars
end
def feature_flags_menu_item
unless can?(context.current_user, :read_feature_flag, context.project)
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
......
......@@ -84,9 +84,7 @@ module Sidebars
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
return ::Sidebars::NilMenuItem.new(item_id: :releases) unless show_releases?
::Sidebars::MenuItem.new(
title: _('Releases'),
......@@ -97,6 +95,12 @@ module Sidebars
)
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)
......
......@@ -7,7 +7,17 @@ module Sidebars
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))
......@@ -17,6 +27,7 @@ module Sidebars
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::OperationsMenu.new(context))
add_menu(Sidebars::Projects::Menus::InfrastructureMenu.new(context))
add_menu(Sidebars::Projects::Menus::PackagesRegistriesMenu.new(context))
......@@ -28,13 +39,6 @@ module Sidebars
add_menu(Sidebars::Projects::Menus::SettingsMenu.new(context))
end
override :aria_label
def aria_label
_('Project navigation')
end
private
def confluence_or_wiki_menu
confluence_menu = ::Sidebars::Projects::Menus::ConfluenceMenu.new(context)
......
......@@ -91,8 +91,6 @@ RSpec.describe 'Project navbar' do
_('Error Tracking'),
_('Alerts'),
_('Incidents'),
_('Environments'),
_('Feature Flags'),
_('Product Analytics')
]
end
......@@ -102,7 +100,6 @@ RSpec.describe 'Project navbar' do
nav_item: _('Project information'),
nav_sub_items: [
_('Activity'),
_('Releases'),
_('Labels')
]
}
......@@ -133,6 +130,18 @@ RSpec.describe 'Project navbar' do
}
)
insert_after_nav_item(
_('Security & Compliance'),
new_nav_item: {
nav_item: _('Deployments'),
nav_sub_items: [
_('Feature Flags'),
_('Environments'),
_('Releases')
]
}
)
visit project_path(project)
end
......
......@@ -178,33 +178,45 @@ RSpec.describe 'User uses shortcuts', :js do
end
end
context 'when navigating to the Operations pages' do
it 'redirects to the Metrics page' do
context 'when navigating to the Deployments page' do
it 'redirects to the Environments page' do
find('body').native.send_key('g')
find('body').native.send_key('l')
find('body').native.send_key('e')
expect(page).to have_active_navigation('Operations')
expect(page).to have_active_sub_navigation('Metrics')
expect(page).to have_active_navigation('Deployments')
expect(page).to have_active_sub_navigation('Environments')
end
end
it 'redirects to the Environments page' do
context 'when navigating to the Operations pages' do
it 'redirects to the Metrics page' do
find('body').native.send_key('g')
find('body').native.send_key('e')
find('body').native.send_key('l')
expect(page).to have_active_navigation('Operations')
expect(page).to have_active_sub_navigation('Environments')
expect(page).to have_active_sub_navigation('Metrics')
end
context 'when feature flag :sidebar_refactor is disabled' do
it 'redirects to the Kubernetes page with active Operations' do
before do
stub_feature_flags(sidebar_refactor: false)
end
it 'redirects to the Kubernetes page with active Operations' do
find('body').native.send_key('g')
find('body').native.send_key('k')
expect(page).to have_active_navigation('Operations')
expect(page).to have_active_sub_navigation('Kubernetes')
end
it 'redirects to the Environments page' do
find('body').native.send_key('g')
find('body').native.send_key('e')
expect(page).to have_active_navigation('Operations')
expect(page).to have_active_sub_navigation('Environments')
end
end
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Projects::Menus::DeploymentsMenu do
let_it_be(:project) { create(:project, :repository) }
let(:user) { project.owner }
let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) }
describe '#render?' do
subject { described_class.new(context) }
context 'when menu does not have any menu items' do
it 'returns false' do
allow(subject).to receive(:has_renderable_items?).and_return(false)
expect(subject.render?).to be false
end
end
context 'when menu has menu items' do
it 'returns true' do
expect(subject.render?).to be true
end
end
end
describe 'Menu Items' do
subject { described_class.new(context).renderable_items.index { |e| e.item_id == item_id } }
shared_examples 'access rights checks' do
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
shared_examples 'feature flag :sidebar_refactor disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.to be_nil }
end
describe 'Feature Flags' do
let(:item_id) { :feature_flags }
it_behaves_like 'access rights checks'
it_behaves_like 'feature flag :sidebar_refactor disabled'
end
describe 'Environments' do
let(:item_id) { :environments }
it_behaves_like 'access rights checks'
it_behaves_like 'feature flag :sidebar_refactor disabled'
end
describe 'Releases' do
let(:item_id) { :releases }
it_behaves_like 'access rights checks'
it_behaves_like 'feature flag :sidebar_refactor disabled'
end
end
end
......@@ -56,9 +56,7 @@ RSpec.describe Sidebars::Projects::Menus::OperationsMenu do
context 'Menu items' do
subject { described_class.new(context).renderable_items.index { |e| e.item_id == item_id } }
describe 'Metrics Dashboard' do
let(:item_id) { :metrics }
shared_examples 'access rights checks' do
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
......@@ -68,153 +66,109 @@ RSpec.describe Sidebars::Projects::Menus::OperationsMenu do
end
end
describe 'Logs' do
let(:item_id) { :logs }
describe 'Metrics Dashboard' do
let(:item_id) { :metrics }
specify { is_expected.not_to be_nil }
it_behaves_like 'access rights checks'
end
describe 'when the user does not have access' do
let(:user) { nil }
describe 'Logs' do
let(:item_id) { :logs }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
describe 'Tracing' do
let(:item_id) { :tracing }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
describe 'Error Tracking' do
let(:item_id) { :error_tracking }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
describe 'Alert Management' do
let(:item_id) { :alert_management }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
describe 'Incidents' do
let(:item_id) { :incidents }
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
describe 'Serverless' do
let(:item_id) { :serverless }
context 'when feature flag :sidebar_refactor is enabled' do
specify { is_expected.to be_nil }
end
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
end
describe 'Terraform' do
let(:item_id) { :terraform }
context 'when feature flag :sidebar_refactor is enabled' do
specify { is_expected.to be_nil }
end
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
end
describe 'Kubernetes' do
let(:item_id) { :kubernetes }
context 'when feature flag :sidebar_refactor is enabled' do
specify { is_expected.to be_nil }
end
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.not_to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
it_behaves_like 'access rights checks'
end
end
describe 'Environments' do
let(:item_id) { :environments }
specify { is_expected.not_to be_nil }
specify { is_expected.to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.to be_nil }
it_behaves_like 'access rights checks'
end
end
describe 'Feature Flags' do
let(:item_id) { :feature_flags }
specify { is_expected.not_to be_nil }
specify { is_expected.to be_nil }
describe 'when the user does not have access' do
let(:user) { nil }
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
specify { is_expected.to be_nil }
it_behaves_like 'access rights checks'
end
end
......
......@@ -14,6 +14,13 @@ RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu do
describe 'Releases' do
let(:item_id) { :releases }
specify { is_expected.to be_nil }
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
context 'when project repository is empty' do
it 'does not include releases menu item' do
allow(project).to receive(:empty_repo?).and_return(true)
......@@ -24,16 +31,13 @@ RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu do
context 'when project repository is not empty' do
context 'when user can download code' do
it 'includes releases menu item' do
is_expected.to be_present
end
specify { is_expected.not_to be_nil }
end
context 'when user cannot download code' do
let(:user) { nil }
it 'does not include releases menu item' do
is_expected.to be_nil
specify { is_expected.to be_nil }
end
end
end
......
......@@ -66,12 +66,22 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
describe 'Releases' do
it 'does not have a link to the project releases path' do
render
expect(rendered).not_to have_link('Releases', href: project_releases_path(project), class: 'shortcuts-project-releases')
end
context 'when feature flag :sidebar refactor is disabled' do
it 'has a link to the project releases path' do
stub_feature_flags(sidebar_refactor: false)
render
expect(rendered).to have_link('Releases', href: project_releases_path(project), class: 'shortcuts-project-releases')
end
end
end
describe 'Labels' do
let(:page) { Nokogiri::HTML.parse(rendered) }
......@@ -417,6 +427,86 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
describe 'Deployments' do
let(:page) { Nokogiri::HTML.parse(rendered) }
describe 'Feature Flags' do
it 'has a link to the feature flags page' do
render
expect(page.at_css('.shortcuts-deployments').parent.css('[aria-label="Feature Flags"]')).not_to be_empty
expect(rendered).to have_link('Feature Flags', href: project_feature_flags_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the feature flags page' do
render
expect(rendered).not_to have_link('Feature Flags')
end
end
context 'when feature flag :sidebar_refactor is disabled' do
it 'does not have a Feature Flags menu item' do
stub_feature_flags(sidebar_refactor: false)
render
expect(rendered).not_to have_selector('.shortcuts-deployments')
end
end
end
describe 'Environments' do
it 'has a link to the environments page' do
render
expect(page.at_css('.shortcuts-deployments').parent.css('[aria-label="Environments"]')).not_to be_empty
expect(rendered).to have_link('Environments', href: project_environments_path(project))
end
describe 'when the user does not have access' do
let(:user) { nil }
it 'does not have a link to the environments page' do
render
expect(rendered).not_to have_link('Environments')
end
end
context 'when feature flag :sidebar_refactor is disabled' do
it 'does not have a Environments menu item' do
stub_feature_flags(sidebar_refactor: false)
render
expect(rendered).not_to have_selector('.shortcuts-deployments')
end
end
end
describe 'Releases' do
it 'has a link to the project releases path' do
render
expect(rendered).to have_link('Releases', href: project_releases_path(project), class: 'shortcuts-deployments-releases')
end
context 'when feature flag :sidebar refactor is disabled' do
it 'does not have a link to the project releases path' do
stub_feature_flags(sidebar_refactor: false)
render
expect(rendered).not_to have_link('Releases', href: project_releases_path(project), class: 'shortcuts-deployments-releases')
end
end
end
end
describe 'Operations' do
it 'top level navigation link is visible for user with permissions' do
render
......@@ -610,9 +700,23 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
describe 'Environments' do
let(:page) { Nokogiri::HTML.parse(rendered) }
it 'does not have a link to the environments page' do
render
expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Environments"]')).to be_empty
end
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
it 'has a link to the environments page' do
render
expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Environments"]')).not_to be_empty
expect(rendered).to have_link('Environments', href: project_environments_path(project))
end
......@@ -626,11 +730,26 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
end
end
describe 'Feature Flags' do
let(:page) { Nokogiri::HTML.parse(rendered) }
it 'does not have a link to the feature flags page' do
render
expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Feature Flags"]')).to be_empty
end
context 'when feature flag :sidebar_refactor is disabled' do
before do
stub_feature_flags(sidebar_refactor: false)
end
it 'has a link to the feature flags page' do
render
expect(page.at_css('.shortcuts-operations').parent.css('[aria-label="Feature Flags"]')).not_to be_empty
expect(rendered).to have_link('Feature Flags', href: project_feature_flags_path(project))
end
......@@ -644,6 +763,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
end
end
end
end
describe 'Product Analytics' do
it 'has a link to the product analytics page' do
......
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