Commit 7915f7e1 authored by Andy Soiron's avatar Andy Soiron

Merge branch '328514-add-settings-menu' into 'master'

Add Settings menu to new Sidebar

See merge request gitlab-org/gitlab!68258
parents e159cc3c 36ffe891
# frozen_string_literal: true
module GroupsHelper
def group_settings_nav_link_paths
%w[
groups#projects
groups#edit
badges#index
repository#show
ci_cd#show
integrations#index
integrations#edit
ldap_group_links#index
hooks#index
pipeline_quota#index
applications#index
applications#show
applications#edit
packages_and_registries#show
groups/runners#show
groups/runners#edit
]
end
def group_sidebar_links
@group_sidebar_links ||= get_group_sidebar_links
end
......
- if @group.packages_feature_enabled?
= nav_link(controller: :packages_and_registries) do
= link_to group_settings_packages_and_registries_path(@group), title: _('Packages & Registries'), data: { qa_selector: 'group_package_settings_link' } do
%span
= _('Packages & Registries')
- if group_sidebar_link?(:settings)
= nav_link(path: group_settings_nav_link_paths) do
= link_to edit_group_path(@group), class: 'has-sub-items' do
.nav-icon-container
= sprite_icon('settings')
%span.nav-item-name{ data: { qa_selector: 'group_settings' } }
= _('Settings')
%ul.sidebar-sub-level-items{ data: { testid: 'group-settings-menu', qa_selector: 'group_sidebar_submenu' } }
= nav_link(path: %w[groups#projects groups#edit badges#index ci_cd#show groups/applications#index], html_options: { class: "fly-out-top-item" } ) do
= link_to edit_group_path(@group) do
%strong.fly-out-top-item-name
= _('Settings')
%li.divider.fly-out-top-item
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group), title: _('General'), data: { qa_selector: 'general_settings_link' } do
%span
= _('General')
= nav_link(controller: :integrations) do
= link_to group_settings_integrations_path(@group), title: _('Integrations') do
%span
= _('Integrations')
= nav_link(path: 'groups#projects') do
= link_to projects_group_path(@group), title: _('Projects') do
%span
= _('Projects')
= nav_link(controller: :repository) do
= link_to group_settings_repository_path(@group), title: _('Repository') do
%span
= _('Repository')
= nav_link(path: ['groups/runners#show', 'groups/runners#edit'], controller: [:ci_cd]) do
= link_to group_settings_ci_cd_path(@group), title: _('CI/CD') do
%span
= _('CI/CD')
= nav_link(controller: :applications) do
= link_to group_settings_applications_path(@group), title: _('Applications') do
%span
= _('Applications')
= render 'groups/sidebar/packages_settings'
= render_if_exists "groups/ee/settings_nav"
= render_if_exists "groups/ee/administration_nav"
= render 'shared/sidebar_toggle_button'
......@@ -8,14 +8,6 @@ module EE
%w[saml_providers#show usage_quotas#index billings#index]
end
def group_settings_nav_link_paths
if ::Feature.disabled?(:group_administration_nav_item, @group)
super + group_nav_link_paths
else
super
end
end
def group_administration_nav_link_paths
group_nav_link_paths
end
......
......@@ -6,10 +6,6 @@ module EE
can?(current_user, :admin_group_saml, group)
end
def show_saml_group_links_in_sidebar?(group)
can?(current_user, :admin_saml_group_links, group)
end
def saml_link_for_provider(text, provider, **args)
saml_link(text, provider.group.full_path, **args)
end
......
......@@ -15,6 +15,7 @@ module EE
override :group_sidebar_context_data
def group_sidebar_context_data(group, user)
super.merge(
show_promotions: show_promotions?(user),
show_discover_group_security: show_discover_group_security?(group)
)
end
......
- administration_nav_item_disabled = Feature.disabled?(:group_administration_nav_item, @group)
- if Gitlab::Auth::Ldap::Config.group_sync_enabled? && can?(current_user, :admin_ldap_group_links, @group)
= nav_link(path: 'ldap_group_links#index') do
= link_to group_ldap_group_links_path(@group), title: 'LDAP Group', class: 'qa-ldap-synchronization-link' do
%span
LDAP Synchronization
- if show_saml_in_sidebar?(@group) && administration_nav_item_disabled
= nav_link(path: 'saml_providers#show') do
= link_to group_saml_providers_path(@group), title: _('SAML SSO'), data: { qa_selector: 'group_saml_sso_link' } do
%span
= _('SAML SSO')
- if show_saml_group_links_in_sidebar?(@group)
= nav_link(path: 'saml_group_links#index') do
= link_to group_saml_group_links_path(@group), title: s_('GroupSAML|SAML Group Links') do
%span
= s_('GroupSAML|SAML Group Links')
- if @group.licensed_feature_available?(:group_webhooks) || show_promotions?
= nav_link(path: 'hooks#index') do
= link_to group_hooks_path(@group), title: 'Webhooks' do
%span
Webhooks
- if show_usage_quotas_in_sidebar? && @group.parent.nil? && administration_nav_item_disabled
= nav_link(path: 'usage_quotas#index') do
= link_to group_usage_quotas_path(@group), title: s_('UsageQuota|Usage Quotas') do
%span
= s_('UsageQuota|Usage Quotas')
- if show_billing_in_sidebar? && administration_nav_item_disabled
= nav_link(path: 'billings#index') do
= link_to group_billings_path(@group), title: _('Billing'), data: { qa_selector: 'billing_link' } do
%span
= _('Billing')
# frozen_string_literal: true
module EE
module Sidebars
module Groups
module Menus
module SettingsMenu
extend ::Gitlab::Utils::Override
include ::Gitlab::Utils::StrongMemoize
override :configure_menu_items
def configure_menu_items
return false unless super
add_item(ldap_sync_menu_item)
add_item(saml_sso_menu_item)
add_item(saml_group_links_menu_item)
add_item(webhooks_menu_item)
add_item(usage_quotas_menu_item)
add_item(billing_menu_item)
true
end
private
def ldap_sync_menu_item
unless ldap_sync_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :ldap_sync)
end
::Sidebars::MenuItem.new(
title: _('LDAP Synchronization'),
link: group_ldap_group_links_path(context.group),
active_routes: { path: 'ldap_group_links#index' },
item_id: :ldap_sync
)
end
def ldap_sync_enabled?
::Gitlab::Auth::Ldap::Config.group_sync_enabled? &&
can?(context.current_user, :admin_ldap_group_links, context.group)
end
def saml_sso_menu_item
unless saml_sso_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :saml_sso)
end
::Sidebars::MenuItem.new(
title: _('SAML SSO'),
link: group_saml_providers_path(context.group),
active_routes: { path: 'saml_providers#show' },
item_id: :saml_sso
)
end
def saml_sso_enabled?
can?(context.current_user, :admin_group_saml, context.group) &&
administration_nav_item_disabled?
end
def saml_group_links_menu_item
unless can?(context.current_user, :admin_saml_group_links, context.group)
return ::Sidebars::NilMenuItem.new(item_id: :saml_group_links)
end
::Sidebars::MenuItem.new(
title: s_('GroupSAML|SAML Group Links'),
link: group_saml_group_links_path(context.group),
active_routes: { path: 'saml_group_links#index' },
item_id: :saml_group_links
)
end
def webhooks_menu_item
unless webhooks_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :webhooks)
end
::Sidebars::MenuItem.new(
title: _('Webhooks'),
link: group_hooks_path(context.group),
active_routes: { path: 'hooks#index' },
item_id: :webhooks
)
end
def webhooks_enabled?
context.group.licensed_feature_available?(:group_webhooks) ||
context.show_promotions
end
def usage_quotas_menu_item
unless usage_quotas_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :usage_quotas)
end
::Sidebars::MenuItem.new(
title: s_('UsageQuota|Usage Quotas'),
link: group_usage_quotas_path(context.group),
active_routes: { path: 'usage_quotas#index' },
item_id: :usage_quotas
)
end
def usage_quotas_enabled?
::License.feature_available?(:usage_quotas) &&
context.group.parent.nil? &&
administration_nav_item_disabled?
end
def billing_menu_item
unless billing_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :billing)
end
::Sidebars::MenuItem.new(
title: _('Billing'),
link: group_billings_path(context.group),
active_routes: { path: 'billings#index' },
item_id: :billing
)
end
def billing_enabled?
::Gitlab::CurrentSettings.should_check_namespace_plan? &&
administration_nav_item_disabled?
end
def administration_nav_item_disabled?
strong_memoize(:administration_nav_item_disabled) do
::Feature.disabled?(:group_administration_nav_item, context.group)
end
end
end
end
end
end
end
......@@ -33,24 +33,4 @@ RSpec.describe EE::SamlProvidersHelper do
it { is_expected.to eq(false) }
end
end
describe '#show_saml_group_links_in_sidebar?' do
subject { helper.show_saml_group_links_in_sidebar?(group) }
context 'when the user can admin saml group links' do
before do
stub_can(:admin_saml_group_links, true)
end
it { is_expected.to eq(true) }
end
context 'when the user cannot admin saml group links' do
before do
stub_can(:admin_saml_group_links, false)
end
it { is_expected.to eq(false) }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Groups::Menus::SettingsMenu do
let_it_be(:owner) { create(:user) }
let_it_be_with_refind(:group) do
build(:group, :private).tap do |g|
g.add_owner(owner)
end
end
let(:user) { owner }
let(:show_promotions) { false }
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group, show_promotions: show_promotions) }
let(:menu) { described_class.new(context) }
describe 'Menu Items' do
subject { menu.renderable_items.find { |e| e.item_id == item_id} }
describe 'LDAP sync menu' do
let(:item_id) { :ldap_sync }
before do
allow(Gitlab::Auth::Ldap::Config).to receive(:group_sync_enabled?).and_return(sync_enabled)
end
context 'when group LDAP sync is not enabled' do
let(:sync_enabled) { false }
specify { is_expected.to be_nil }
end
context 'when group LDAP sync is enabled' do
let(:sync_enabled) { true }
context 'when user can admin LDAP syncs' do
specify { is_expected.to be_present }
end
context 'when user cannot admin LDAP syncs' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
end
describe 'SAML SSO menu' do
let(:item_id) { :saml_sso }
let(:group_admin_nav_enabled) { false }
let(:saml_enabled) { true }
before do
stub_feature_flags(group_administration_nav_item: group_admin_nav_enabled)
stub_licensed_features(group_saml: saml_enabled)
allow(::Gitlab::Auth::GroupSaml::Config).to receive(:enabled?).and_return(saml_enabled)
end
context 'when SAML is disabled' do
let(:saml_enabled) { false }
specify { is_expected.to be_nil }
end
context 'when SAML is enabled' do
context 'when :group_administration_nav_item feature is disabled' do
specify { is_expected.to be_present }
context 'when user cannot admin group SAML' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
context 'when :group_administration_nav_item feature is enabled' do
let(:group_admin_nav_enabled) { true }
specify { is_expected.to be_nil }
end
end
end
describe 'SAML group links menu' do
let(:item_id) { :saml_group_links }
let(:saml_group_links_enabled) { true }
before do
allow(::Gitlab::Auth::GroupSaml::Config).to receive(:enabled?).and_return(saml_group_links_enabled)
allow(group).to receive(:saml_group_sync_available?).and_return(saml_group_links_enabled)
end
context 'when SAML group links feature is disabled' do
let(:saml_group_links_enabled) { false }
specify { is_expected.to be_nil }
end
context 'when SAML group links feature is enabled' do
specify { is_expected.to be_present }
context 'when user cannot admin SAML group links' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
end
describe 'Webhooks menu' do
let(:item_id) { :webhooks }
let(:group_webhooks_enabled) { true }
before do
stub_licensed_features(group_webhooks: group_webhooks_enabled)
end
context 'when licensed feature :group_webhooks is not enabled' do
let(:group_webhooks_enabled) { false }
specify { is_expected.to be_nil }
end
context 'when show_promotions is enabled' do
let(:show_promotions) { true }
specify { is_expected.to be_present }
end
context 'when licensed feature :group_webhooks is enabled' do
specify { is_expected.to be_present }
end
end
describe 'Usage quotas menu' do
let(:item_id) { :usage_quotas }
let(:group_admin_nav_enabled) { false }
let(:usage_quotas_enabled) { true }
before do
stub_feature_flags(group_administration_nav_item: group_admin_nav_enabled)
stub_licensed_features(usage_quotas: usage_quotas_enabled)
end
specify { is_expected.to be_present }
context 'when feature flag :group_administration_nav_item is enabled' do
let(:group_admin_nav_enabled) { true }
specify { is_expected.to be_nil }
end
context 'when usage_quotas licensed feature is not enabled' do
let(:usage_quotas_enabled) { false }
specify { is_expected.to be_nil }
end
end
describe 'Billing menu' do
let(:item_id) { :billing }
let(:group_admin_nav_enabled) { false }
let(:check_billing) { true }
before do
stub_feature_flags(group_administration_nav_item: group_admin_nav_enabled)
allow(::Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?).and_return(check_billing)
end
specify { is_expected.to be_present }
context 'when feature flag :group_administration_nav_item is enabled' do
let(:group_admin_nav_enabled) { true }
specify { is_expected.to be_nil }
end
context 'when group billing does not apply' do
let(:check_billing) { false }
specify { is_expected.to be_nil }
end
end
end
end
......@@ -611,4 +611,48 @@ RSpec.describe 'layouts/nav/sidebar/_group' do
end
end
end
describe 'Settings' do
let(:administration_nav_enabled) { true }
before do
group.add_owner(user)
stub_licensed_features(usage_quotas: true)
stub_feature_flags(group_administration_nav_item: false)
allow(::Gitlab::CurrentSettings).to receive(:should_check_namespace_plan?).and_return(true)
allow(::Gitlab::Auth::Ldap::Config).to receive(:group_sync_enabled?).and_return(true)
allow(group).to receive(:saml_group_sync_available?).and_return(true)
allow(group).to receive(:feature_available?).and_call_original
allow(group).to receive(:feature_available?).with(:group_saml).and_return(true)
allow(view).to receive(:current_user).and_return(user)
render
end
it 'has a link to the LDAP sync settings page' do
expect(rendered).to have_link('LDAP Synchronization', href: group_ldap_group_links_path(group))
end
it 'has a link to the SAML SSO settings page' do
expect(rendered).to have_link('SAML SSO', href: group_saml_providers_path(group))
end
it 'has a link to the SAML group links settings page' do
expect(rendered).to have_link('SAML Group Links', href: group_saml_group_links_path(group))
end
it 'has a link to the Webhooks settings page' do
expect(rendered).to have_link('Webhooks', href: group_hooks_path(group))
end
it 'has a link to the Usage Quotas settings page' do
expect(rendered).to have_link('Usage Quotas', href: group_usage_quotas_path(group))
end
it 'has a link to the Billing settings page' do
expect(rendered).to have_link('Billing', href: group_billings_path(group))
end
end
end
# frozen_string_literal: true
module Sidebars
module Groups
module Menus
class SettingsMenu < ::Sidebars::Menu
override :configure_menu_items
def configure_menu_items
return false unless can?(context.current_user, :admin_group, context.group)
add_item(general_menu_item)
add_item(integrations_menu_item)
add_item(group_projects_menu_item)
add_item(repository_menu_item)
add_item(ci_cd_menu_item)
add_item(applications_menu_item)
add_item(packages_and_registries_menu_item)
true
end
override :link
def link
edit_group_path(context.group)
end
override :title
def title
_('Settings')
end
override :sprite_icon
def sprite_icon
'settings'
end
override :extra_nav_link_html_options
def extra_nav_link_html_options
{
class: 'shortcuts-settings'
}
end
private
def general_menu_item
::Sidebars::MenuItem.new(
title: _('General'),
link: edit_group_path(context.group),
active_routes: { path: 'groups#edit' },
item_id: :general
)
end
def integrations_menu_item
::Sidebars::MenuItem.new(
title: _('Integrations'),
link: group_settings_integrations_path(context.group),
active_routes: { controller: :integrations },
item_id: :integrations
)
end
def group_projects_menu_item
::Sidebars::MenuItem.new(
title: _('Projects'),
link: projects_group_path(context.group),
active_routes: { path: 'groups#projects' },
item_id: :group_projects
)
end
def repository_menu_item
::Sidebars::MenuItem.new(
title: _('Repository'),
link: group_settings_repository_path(context.group),
active_routes: { controller: :repository },
item_id: :repository
)
end
def ci_cd_menu_item
::Sidebars::MenuItem.new(
title: _('CI/CD'),
link: group_settings_ci_cd_path(context.group),
active_routes: { path: %w[ci_cd#show groups/runners#show groups/runners#edit] },
item_id: :ci_cd
)
end
def applications_menu_item
::Sidebars::MenuItem.new(
title: _('Applications'),
link: group_settings_applications_path(context.group),
active_routes: { controller: :applications },
item_id: :applications
)
end
def packages_and_registries_menu_item
unless context.group.packages_feature_enabled?
return ::Sidebars::NilMenuItem.new(item_id: :packages_and_registries)
end
::Sidebars::MenuItem.new(
title: _('Packages & Registries'),
link: group_settings_packages_and_registries_path(context.group),
active_routes: { controller: :packages_and_registries },
item_id: :packages_and_registries
)
end
end
end
end
end
Sidebars::Groups::Menus::SettingsMenu.prepend_mod_with('Sidebars::Groups::Menus::SettingsMenu')
......@@ -13,6 +13,7 @@ module Sidebars
add_menu(Sidebars::Groups::Menus::CiCdMenu.new(context))
add_menu(Sidebars::Groups::Menus::KubernetesMenu.new(context))
add_menu(Sidebars::Groups::Menus::PackagesRegistriesMenu.new(context))
add_menu(Sidebars::Groups::Menus::SettingsMenu.new(context))
end
override :render_raw_menus_partial
......
......@@ -13,21 +13,11 @@ module QA
base.class_eval do
prepend QA::Page::Group::SubMenus::Common
view 'app/views/layouts/nav/sidebar/_group_menus.html.haml' do
element :group_sidebar_submenu
element :group_settings
end
view 'ee/app/views/groups/ee/_administration_nav.html.haml' do
element :group_administration_link
element :group_sidebar_submenu_content
element :group_saml_sso_link
end
view 'ee/app/views/groups/ee/_settings_nav.html.haml' do
element :ldap_synchronization_link
element :billing_link
end
end
end
......@@ -56,9 +46,9 @@ module QA
end
def go_to_ldap_sync_settings
hover_element(:group_settings) do
within_submenu(:group_sidebar_submenu) do
click_element(:ldap_synchronization_link)
hover_group_settings do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'LDAP Synchronization')
end
end
end
......@@ -79,14 +69,6 @@ module QA
end
end
def click_group_general_settings_item
hover_element(:group_settings) do
within_submenu(:group_sidebar_submenu) do
click_element(:general_settings_link)
end
end
end
def click_group_epics_link
within_sidebar do
click_element(:sidebar_menu_link, menu_item: 'Epics')
......@@ -125,9 +107,9 @@ module QA
end
def go_to_billing
hover_element(:group_settings) do
within_submenu(:group_sidebar_submenu) do
click_element(:billing_link)
hover_group_settings do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'Billing')
end
end
end
......
......@@ -6,15 +6,6 @@ module QA
class Menu < Page::Base
include SubMenus::Common
view 'app/views/layouts/nav/sidebar/_group_menus.html.haml' do
element :general_settings_link
element :group_settings
end
view 'app/views/groups/sidebar/_packages_settings.html.haml' do
element :group_package_settings_link
end
def click_group_members_item
hover_group_information do
within_submenu do
......@@ -33,14 +24,14 @@ module QA
def click_settings
within_sidebar do
click_element(:group_settings)
click_element(:sidebar_menu_link, menu_item: 'Settings')
end
end
def click_group_general_settings_item
hover_element(:group_settings) do
within_submenu(:group_sidebar_submenu) do
click_element(:general_settings_link)
hover_group_settings do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'General')
end
end
end
......@@ -54,10 +45,9 @@ module QA
end
def go_to_package_settings
scroll_to_element(:group_settings)
hover_element(:group_settings) do
within_submenu(:group_sidebar_submenu) do
click_element(:group_package_settings_link)
hover_group_settings do
within_submenu do
click_element(:sidebar_menu_item_link, menu_item: 'Packages & Registries')
end
end
end
......@@ -113,6 +103,15 @@ module QA
yield
end
end
def hover_group_settings
within_sidebar do
scroll_to_element(:sidebar_menu_link, menu_item: 'Settings')
find_element(:sidebar_menu_link, menu_item: 'Settings').hover
yield
end
end
end
end
end
......
......@@ -113,7 +113,7 @@ RSpec.describe 'Group Packages & Registries settings' do
end
def find_settings_menu
find('ul[data-testid="group-settings-menu"]')
find('.shortcuts-settings ul')
end
def visit_settings_page
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Sidebars::Groups::Menus::SettingsMenu do
let_it_be(:owner) { create(:user) }
let_it_be_with_refind(:group) do
build(:group, :private).tap do |g|
g.add_owner(owner)
end
end
let(:user) { owner }
let(:context) { Sidebars::Groups::Context.new(current_user: user, container: group) }
let(:menu) { described_class.new(context) }
describe '#render?' do
context 'when user cannot admin group' do
let(:user) { nil }
it 'returns false' do
expect(menu.render?).to be false
end
end
end
describe 'Menu items' do
subject { menu.renderable_items.find { |e| e.item_id == item_id } }
shared_examples 'access rights checks' do
specify { is_expected.not_to be_nil }
context 'when the user does not have access' do
let(:user) { nil }
specify { is_expected.to be_nil }
end
end
describe 'General menu' do
let(:item_id) { :general }
it_behaves_like 'access rights checks'
end
describe 'Integrations menu' do
let(:item_id) { :integrations }
it_behaves_like 'access rights checks'
end
describe 'Projects menu' do
let(:item_id) { :group_projects }
it_behaves_like 'access rights checks'
end
describe 'Repository menu' do
let(:item_id) { :repository }
it_behaves_like 'access rights checks'
end
describe 'CI/CD menu' do
let(:item_id) { :ci_cd }
it_behaves_like 'access rights checks'
end
describe 'Applications menu' do
let(:item_id) { :applications }
it_behaves_like 'access rights checks'
end
describe 'Packages & Registries' do
let(:item_id) { :packages_and_registries }
before do
allow(group).to receive(:packages_feature_enabled?).and_return(packages_enabled)
end
describe 'when packages feature is disabled' do
let(:packages_enabled) { false }
specify { is_expected.to be_nil }
end
describe 'when packages feature is enabled' do
let(:packages_enabled) { true }
it_behaves_like 'access rights checks'
end
end
end
end
......@@ -134,4 +134,54 @@ RSpec.describe 'layouts/nav/sidebar/_group' do
expect(rendered).to have_link('Dependency Proxy', href: group_dependency_proxy_path(group))
end
end
describe 'Settings' do
it 'default link points to edit group page' do
render
expect(rendered).to have_link('Settings', href: edit_group_path(group))
end
it 'has a link to the General settings page' do
render
expect(rendered).to have_link('General', href: edit_group_path(group))
end
it 'has a link to the Integrations settings page' do
render
expect(rendered).to have_link('Integrations', href: group_settings_integrations_path(group))
end
it 'has a link to the group Projects settings page' do
render
expect(rendered).to have_link('Projects', href: projects_group_path(group))
end
it 'has a link to the Repository settings page' do
render
expect(rendered).to have_link('Repository', href: group_settings_repository_path(group))
end
it 'has a link to the CI/CD settings page' do
render
expect(rendered).to have_link('CI/CD', href: group_settings_ci_cd_path(group))
end
it 'has a link to the Applications settings page' do
render
expect(rendered).to have_link('Applications', href: group_settings_applications_path(group))
end
it 'has a link to the Package & Registries settings page' do
render
expect(rendered).to have_link('Packages & Registries', href: group_settings_packages_and_registries_path(group))
end
end
end
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